From 5ce79bd2b870fa280f42ace4ea2056791b7b9125 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 24 Aug 2022 14:17:31 +0100 Subject: [PATCH 01/13] nightly task to automatically PR and merge changes from main into release --- .github/workflows/nightly.yml | 31 ++++++ .gitignore | 3 +- tools/beta-release/app.js | 138 +++++++++++++++++++++++++++ tools/beta-release/package-lock.json | 13 +++ tools/beta-release/package.json | 8 ++ 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/nightly.yml create mode 100644 tools/beta-release/app.js create mode 100644 tools/beta-release/package-lock.json create mode 100644 tools/beta-release/package.json diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000..945a0de --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,31 @@ +name: Nightly + +on: + schedule: + - cron: '0 19 * * *' + +jobs: + check-develop-beta-changes: + name: Check if develop is ahead of beta release + runs-on: ubuntu-latest + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-node@v3 + with: + node-version: + 16 + - run: npm ci + working-directory: ./tools/beta-release/ + + - uses: actions/github-script@v6 + with: + script: | + const { script } = await import('${{ github.workspace }}/tools/beta-release/app.js') + await script({github, context, core}) + diff --git a/.gitignore b/.gitignore index 3b76762..9257dec 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ .externalNativeBuild .cxx local.properties -/benchmark-out \ No newline at end of file +/benchmark-out +**/node_modules \ No newline at end of file diff --git a/tools/beta-release/app.js b/tools/beta-release/app.js new file mode 100644 index 0000000..b0ebf35 --- /dev/null +++ b/tools/beta-release/app.js @@ -0,0 +1,138 @@ +const config = { + owner: "ouchadam", + repo: "small-talk", + pathToVersionFile: "version.json", + rcBranchesFrom: "main", + rcMergesTo: "release", +} + +const rcBranchName = "release-candidate" + +export const script = async ({ github, context, core }) => { + console.log("script start") + if (await doesNotHaveInProgressRelease(github) && await isWorkingBranchAhead(github)) { + await startRelease(github) + } else { + console.log(`Release skipped due to being behind`) + } + return "" +} + +const isWorkingBranchAhead = async (github) => { + const result = await github.rest.repos.compareCommitsWithBasehead({ + owner: config.owner, + repo: config.repo, + basehead: `${config.rcMergesTo}...${config.rcBranchesFrom}`, + per_page: 1, + page: 1, + }) + return result.data.status === "ahead" +} + +const doesNotHaveInProgressRelease = async (github) => { + const releasePrs = await github.rest.pulls.list({ + owner: config.owner, + repo: config.repo, + state: "open", + base: config.rcMergesTo + }) + + const syncPrs = await github.rest.pulls.list({ + owner: config.owner, + repo: config.repo, + state: "open", + base: config.rcBranchesFrom, + head: `${config.owner}:${config.rcMergesTo}` + }) + + return releasePrs.data.length === 0 && syncPrs.data.length === 0 +} + +const startRelease = async (github) => { + console.log(`creating release candidate from head of ${config.rcBranchesFrom}`) + + await createBranch(github, "release-candidate", config.rcBranchesFrom) + await incrementVersionFile(github, rcBranchName) + + const createdPr = await github.rest.pulls.create({ + owner: config.owner, + repo: config.repo, + title: "[Auto] Release Candidate", + head: rcBranchName, + base: config.rcMergesTo, + body: "todo", + }) + + github.graphql( + ` + mutation ($pullRequestId: ID!, $mergeMethod: PullRequestMergeMethod!) { + enablePullRequestAutoMerge(input: { + pullRequestId: $pullRequestId, + mergeMethod: $mergeMethod + }) { + pullRequest { + autoMergeRequest { + enabledAt + enabledBy { + login + } + } + } + } + } + `, + { + pullRequestId: createdPr.data.node_id, + mergeMethod: "MERGE" + } + ) +} + +const createBranch = async (github, branchName, fromBranch) => { + const mainRef = await github.rest.git.getRef({ + owner: config.owner, + repo: config.repo, + ref: `heads/${fromBranch}`, + }) + + await github.rest.git.createRef({ + owner: config.owner, + repo: config.repo, + ref: `refs/heads/${branchName}`, + sha: mainRef.data.object.sha, + }) +} + +const incrementVersionFile = async (github, branchName) => { + const versionFile = await readVersionFile(github) + + const updatedVersionFile = { + ...versionFile.content, + code: versionFile.content.code + 1, + } + const encodedContentUpdate = Buffer.from(JSON.stringify(updatedVersionFile, null, 2)).toString('base64') + await github.rest.repos.createOrUpdateFileContents({ + owner: config.owner, + repo: config.repo, + content: encodedContentUpdate, + path: config.pathToVersionFile, + sha: versionFile.sha, + branch: branchName, + message: "updating version for release", + }) +} + +const readVersionFile = async (github) => { + const result = await github.rest.repos.getContent({ + owner: config.owner, + repo: config.repo, + path: config.pathToVersionFile, + ref: config.rcBranchesFrom, + }) + + const content = Buffer.from(result.data.content, result.data.encoding).toString() + return { + content: JSON.parse(content), + sha: result.data.sha, + } +} \ No newline at end of file diff --git a/tools/beta-release/package-lock.json b/tools/beta-release/package-lock.json new file mode 100644 index 0000000..358934c --- /dev/null +++ b/tools/beta-release/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "beta-release", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "beta-release", + "version": "1.0.0", + "license": "MIT" + } + } +} diff --git a/tools/beta-release/package.json b/tools/beta-release/package.json new file mode 100644 index 0000000..975ce6c --- /dev/null +++ b/tools/beta-release/package.json @@ -0,0 +1,8 @@ +{ + "name": "beta-release", + "version": "1.0.0", + "main": "app.js", + "license": "MIT", + "type": "module", + "private": true +} From cac4f8cedf49de96a491df0ba3d56ea2d436f48f Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 24 Aug 2022 15:15:26 +0100 Subject: [PATCH 02/13] ignoring node modules --- .github/workflows/nightly.yml | 4 ++-- .gitignore | 2 +- app/build.gradle | 7 +++++-- tools/beta-release/app.js | 7 ++++++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 945a0de..8162c56 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -26,6 +26,6 @@ jobs: - uses: actions/github-script@v6 with: script: | - const { script } = await import('${{ github.workspace }}/tools/beta-release/app.js') - await script({github, context, core}) + const { startReleaseProcess } = await import('${{ github.workspace }}/tools/beta-release/app.js') + await startReleaseProcess({github, context, core}) diff --git a/.gitignore b/.gitignore index 9257dec..0f83f23 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ .cxx local.properties /benchmark-out -**/node_modules \ No newline at end of file +/node_modules \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 5ed4c0c..1e87c5c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,8 +46,11 @@ android { "proguard/serializationx.pro", "proguard/olm.pro" - // actual releases are signed with a different config - signingConfig = buildTypes.debug.signingConfig + if (project.hasProperty("unsigned")) { + // releases are signed externally + } else { + signingConfig = buildTypes.debug.signingConfig + } } } diff --git a/tools/beta-release/app.js b/tools/beta-release/app.js index b0ebf35..a430101 100644 --- a/tools/beta-release/app.js +++ b/tools/beta-release/app.js @@ -8,7 +8,7 @@ const config = { const rcBranchName = "release-candidate" -export const script = async ({ github, context, core }) => { +export const startReleaseProcess = async ({ github, context, core }) => { console.log("script start") if (await doesNotHaveInProgressRelease(github) && await isWorkingBranchAhead(github)) { await startRelease(github) @@ -18,6 +18,11 @@ export const script = async ({ github, context, core }) => { return "" } +export const publishRelease = async (github, artifact) => { + +} + + const isWorkingBranchAhead = async (github) => { const result = await github.rest.repos.compareCommitsWithBasehead({ owner: config.owner, From 81c8cb4927f5bf71c31769546c34310847c19ff4 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 24 Aug 2022 15:34:08 +0100 Subject: [PATCH 03/13] updating gitignore to ignore secrets and any nodemodules dir --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0f83f23..b55bcc1 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ .cxx local.properties /benchmark-out -/node_modules \ No newline at end of file +**/node_modules +.secrets \ No newline at end of file From e235598ff526b500aa2dc70c3a97d4d7cfe81898 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 24 Aug 2022 15:34:30 +0100 Subject: [PATCH 04/13] adding script to generate signed release bundle --- tools/generate-release.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 tools/generate-release.sh diff --git a/tools/generate-release.sh b/tools/generate-release.sh new file mode 100755 index 0000000..dc10bf0 --- /dev/null +++ b/tools/generate-release.sh @@ -0,0 +1,10 @@ +#! /bin/bash + +./gradlew clean bundleRelease -Punsigned --no-daemon --no-configuration-cache --no-build-cache +RELEASE_AAB=app/build/outputs/bundle/release/app-release.aab + +jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \ + -keystore .secrets/upload-key.jks \ + -storepass $1 \ + $RELEASE_AAB \ + key0 \ No newline at end of file From 982476e7d6b5fa50b8d5849d34dc624120a3a561 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 24 Aug 2022 15:35:16 +0100 Subject: [PATCH 05/13] adding gh action for generating the signed bundle - doesn't upload anywhere yet... --- .github/workflows/release-candidate.yml | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/release-candidate.yml diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml new file mode 100644 index 0000000..db85502 --- /dev/null +++ b/.github/workflows/release-candidate.yml @@ -0,0 +1,43 @@ + + +# on pushes to release candidate +# create release apk +# create tag, draft github release, upload universal + + +name: Generate and publish Release Candidate + +on: + push: + branches: + - 'release' + +jobs: + publish-release-candidate: + name: Publish release candidate + runs-on: ubuntu-latest + + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: 'adopt' + java-version: '11' + - uses: actions/setup-node@v3 + with: + node-version: + 16 + - run: npm ci + working-directory: ./tools/beta-release/ + + - run: | + mkdir .secrets && touch .secrets/upload-key.jks + echo ${{ secrets.UPLOAD_KEY }} | base64 -d >> .secrets/upload-key.jks + + - name: Assemble release variant + run: ./tools/generate-release.sh ${{ secrets.STORE_PASS }} + From 9f5beb532f67d176fc865f9ae039852ff4b776b6 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 30 Aug 2022 20:32:52 +0100 Subject: [PATCH 06/13] adds automatic beta track deploying and github release creation on merges to the release branch - each merge expects an updated version code --- .github/workflows/release-candidate.yml | 20 +- tools/beta-release/app.js | 15 +- tools/beta-release/package-lock.json | 756 +++++++++++++++++++++++- tools/beta-release/package.json | 5 +- tools/beta-release/release.js | 201 +++++++ tools/generate-release.sh | 9 +- version.json | 4 +- 7 files changed, 993 insertions(+), 17 deletions(-) create mode 100644 tools/beta-release/release.js diff --git a/.github/workflows/release-candidate.yml b/.github/workflows/release-candidate.yml index db85502..7ee6440 100644 --- a/.github/workflows/release-candidate.yml +++ b/.github/workflows/release-candidate.yml @@ -1,10 +1,3 @@ - - -# on pushes to release candidate -# create release apk -# create tag, draft github release, upload universal - - name: Generate and publish Release Candidate on: @@ -35,9 +28,20 @@ jobs: working-directory: ./tools/beta-release/ - run: | - mkdir .secrets && touch .secrets/upload-key.jks + mkdir .secrets && touch .secrets/upload-key.jks && touch .secrets/service-account.json echo ${{ secrets.UPLOAD_KEY }} | base64 -d >> .secrets/upload-key.jks + echo ${{ secrets.SERVICE_ACCOUNT }} | base64 -d >> .secrets/service-account.json - name: Assemble release variant run: ./tools/generate-release.sh ${{ secrets.STORE_PASS }} + - uses: actions/github-script@v6 + with: + script: | + const { publishRelease } = await import('${{ github.workspace }}/tools/beta-release/app.js') + const artifacts = { + bundle: '${{ github.workspace }}/app/build/outputs/bundle/release/app-release.aab', + mapping: '${{ github.workspace }}/app/build/outputs/mapping/release/mapping.txt', + } + await publishRelease(github, artifacts) + diff --git a/tools/beta-release/app.js b/tools/beta-release/app.js index a430101..aeb790c 100644 --- a/tools/beta-release/app.js +++ b/tools/beta-release/app.js @@ -1,9 +1,12 @@ +import { release } from './release.js' + const config = { owner: "ouchadam", repo: "small-talk", pathToVersionFile: "version.json", rcBranchesFrom: "main", rcMergesTo: "release", + packageName: "app.dapk.st" } const rcBranchName = "release-candidate" @@ -18,11 +21,17 @@ export const startReleaseProcess = async ({ github, context, core }) => { return "" } -export const publishRelease = async (github, artifact) => { - +export const publishRelease = async (github, artifacts) => { + const versionFile = await readVersionFile(github) + await release( + github, + versionFile.content, + config.packageName, + artifacts, + config, + ).catch((error) => console.log(error)) } - const isWorkingBranchAhead = async (github) => { const result = await github.rest.repos.compareCommitsWithBasehead({ owner: config.owner, diff --git a/tools/beta-release/package-lock.json b/tools/beta-release/package-lock.json index 358934c..a35258b 100644 --- a/tools/beta-release/package-lock.json +++ b/tools/beta-release/package-lock.json @@ -7,7 +7,761 @@ "": { "name": "beta-release", "version": "1.0.0", - "license": "MIT" + "license": "MIT", + "dependencies": { + "@googleapis/androidpublisher": "^3.0.0" + } + }, + "node_modules/@googleapis/androidpublisher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@googleapis/androidpublisher/-/androidpublisher-3.0.0.tgz", + "integrity": "sha512-r4JfmLlcu/VI4hObZuQ8RW5OeWRFtOxqE9xU8C2GAp3GTu2ZcemEICu69xy/rchpzMNQY4lrr8WiqUG1LE1L5Q==", + "dependencies": { + "googleapis-common": "^5.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "engines": { + "node": ">=8" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fast-text-encoding": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz", + "integrity": "sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ==" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gaxios": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", + "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/google-auth-library": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", + "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-p12-pem": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz", + "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==", + "dependencies": { + "node-forge": "^1.3.1" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/googleapis-common": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.1.0.tgz", + "integrity": "sha512-RXrif+Gzhq1QAzfjxulbGvAY3FPj8zq/CYcvgjzDbaBNCD6bUl+86I7mUs4DKWHGruuK26ijjR/eDpWIDgNROA==", + "dependencies": { + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.14.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "@googleapis/androidpublisher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@googleapis/androidpublisher/-/androidpublisher-3.0.0.tgz", + "integrity": "sha512-r4JfmLlcu/VI4hObZuQ8RW5OeWRFtOxqE9xU8C2GAp3GTu2ZcemEICu69xy/rchpzMNQY4lrr8WiqUG1LE1L5Q==", + "requires": { + "googleapis-common": "^5.0.1" + } + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bignumber.js": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-text-encoding": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz", + "integrity": "sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gaxios": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", + "integrity": "sha512-gSaYYIO1Y3wUtdfHmjDUZ8LWaxJQpiavzbF5Kq53akSzvmVg0RfyOcFDbO1KJ/KCGRFz2qG+lS81F0nkr7cRJA==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.7" + } + }, + "gcp-metadata": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.3.1.tgz", + "integrity": "sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "google-auth-library": { + "version": "7.14.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.14.1.tgz", + "integrity": "sha512-5Rk7iLNDFhFeBYc3s8l1CqzbEBcdhwR193RlD4vSNFajIcINKI8W8P0JLmBpwymHqqWbX34pJDQu39cSy/6RsA==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.1.4.tgz", + "integrity": "sha512-HHuHmkLgwjdmVRngf5+gSmpkyaRI6QmOg77J8tkNBHhNEI62sGHyw4/+UkgyZEI7h84NbWprXDJ+sa3xOYFvTg==", + "requires": { + "node-forge": "^1.3.1" + } + }, + "googleapis-common": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-5.1.0.tgz", + "integrity": "sha512-RXrif+Gzhq1QAzfjxulbGvAY3FPj8zq/CYcvgjzDbaBNCD6bUl+86I7mUs4DKWHGruuK26ijjR/eDpWIDgNROA==", + "requires": { + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "google-auth-library": "^7.14.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^8.0.0" + } + }, + "gtoken": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.3.2.tgz", + "integrity": "sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.1.3", + "jws": "^4.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/tools/beta-release/package.json b/tools/beta-release/package.json index 975ce6c..b36676e 100644 --- a/tools/beta-release/package.json +++ b/tools/beta-release/package.json @@ -4,5 +4,8 @@ "main": "app.js", "license": "MIT", "type": "module", - "private": true + "private": true, + "dependencies": { + "@googleapis/androidpublisher": "^3.0.0" + } } diff --git a/tools/beta-release/release.js b/tools/beta-release/release.js new file mode 100644 index 0000000..94789ce --- /dev/null +++ b/tools/beta-release/release.js @@ -0,0 +1,201 @@ +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 + + console.log(`found ${apks.length} apks`) + apks.forEach((apk) => { + console.log(apk) + }) + + 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) + }) + }) +} + +const promoteDraftToLive = async () => { + const fappEditId = await startPlayRelease(applicationId) + + await androidPublisher.edits.tracks + .update({ + editId: fappEditId, + packageName: applicationId, + track: "beta", + requestBody: { + track: "beta", + releases: [ + { + status: "completed", + } + ] + } + }) + .catch((error) => Promise.reject(error.response.data)) + + + await androidPublisher.edits.commit({ + editId: fappEditId, + packageName: applicationId, + }).catch((error) => Promise.reject(error.response.data)) +} + diff --git a/tools/generate-release.sh b/tools/generate-release.sh index dc10bf0..16ae11f 100755 --- a/tools/generate-release.sh +++ b/tools/generate-release.sh @@ -1,10 +1,15 @@ #! /bin/bash ./gradlew clean bundleRelease -Punsigned --no-daemon --no-configuration-cache --no-build-cache -RELEASE_AAB=app/build/outputs/bundle/release/app-release.aab +WORKING_DIR=app/build/outputs/bundle/release +RELEASE_AAB=$WORKING_DIR/app-release.aab + +cp $RELEASE_AAB $WORKING_DIR/app-release-unsigned.aab + +echo "signing $RELEASE_AAB" jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \ -keystore .secrets/upload-key.jks \ -storepass $1 \ $RELEASE_AAB \ - key0 \ No newline at end of file + key0 diff --git a/version.json b/version.json index dacf613..a85baed 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "name": "0.0.1-alpha03", - "code": 4 + "name": "0.0.1-alpha04", + "code": 6 } \ No newline at end of file From d01451e3e9d7fdf82181d7a7b09adce8c5e26671 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 31 Aug 2022 17:44:17 +0100 Subject: [PATCH 07/13] replacing non foss dependencies with noop replaceable modules when the project is build with the -Pfoss flag --- app/build.gradle | 2 + .../app/dapk/st/SmallTalkApplication.kt | 4 +- .../kotlin/app/dapk/st/graph/AppModule.kt | 19 +++++-- build.gradle | 17 ++++++- domains/android/push/build.gradle | 5 +- .../android/push/src/main/AndroidManifest.xml | 9 ---- .../kotlin/app/dapk/st/push/PushModule.kt | 5 +- .../firebase/FirebaseMessagingExtensions.kt | 18 ------- .../firebase/FirebasePushTokenRegistrar.kt | 27 +++------- ...hService.kt => MessagingServiceAdapter.kt} | 17 +++---- domains/android/tracking/build.gradle | 6 +-- ...sCrashTracker.kt => CrashTrackerLogger.kt} | 6 +-- .../app/dapk/st/tracking/TrackingModule.kt | 20 +++++--- .../firebase/crashlytics-noop/build.gradle | 5 ++ .../firebase/crashlytics/CrashlyticsModule.kt | 16 ++++++ domains/firebase/crashlytics/build.gradle | 7 +++ .../crashlytics/src/main/AndroidManifest.xml | 2 + .../crashlytics/CrashlyticsCrashTracker.kt | 14 ++++++ .../firebase/crashlytics/CrashlyticsModule.kt | 13 +++++ domains/firebase/messaging-noop/build.gradle | 6 +++ .../src/main/AndroidManifest.xml | 2 + .../dapk/st/firebase/messaging/Messaging.kt | 21 ++++++++ .../st/firebase/messaging/MessagingModule.kt | 17 +++++++ .../st/firebase/messaging/ServiceDelegate.kt | 9 ++++ domains/firebase/messaging/build.gradle | 9 ++++ .../messaging/src/main/AndroidManifest.xml | 15 ++++++ .../messaging/FirebasePushServiceDelegate.kt | 26 ++++++++++ .../dapk/st/firebase/messaging/Messaging.kt | 50 +++++++++++++++++++ .../st/firebase/messaging/MessagingModule.kt | 17 +++++++ .../st/firebase/messaging/ServiceDelegate.kt | 9 ++++ settings.gradle | 5 ++ 31 files changed, 311 insertions(+), 87 deletions(-) delete mode 100644 domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebaseMessagingExtensions.kt rename domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/{FirebasePushService.kt => MessagingServiceAdapter.kt} (54%) rename domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/{CrashlyticsCrashTracker.kt => CrashTrackerLogger.kt} (62%) create mode 100644 domains/firebase/crashlytics-noop/build.gradle create mode 100644 domains/firebase/crashlytics-noop/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt create mode 100644 domains/firebase/crashlytics/build.gradle create mode 100644 domains/firebase/crashlytics/src/main/AndroidManifest.xml create mode 100644 domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsCrashTracker.kt create mode 100644 domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt create mode 100644 domains/firebase/messaging-noop/build.gradle create mode 100644 domains/firebase/messaging-noop/src/main/AndroidManifest.xml create mode 100644 domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt create mode 100644 domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt create mode 100644 domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt create mode 100644 domains/firebase/messaging/build.gradle create mode 100644 domains/firebase/messaging/src/main/AndroidManifest.xml create mode 100644 domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/FirebasePushServiceDelegate.kt create mode 100644 domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt create mode 100644 domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt create mode 100644 domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt diff --git a/app/build.gradle b/app/build.gradle index 1e87c5c..3f862b6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,6 +85,8 @@ dependencies { implementation project(":domains:android:imageloader") implementation project(":domains:olm") + firebase(it, "messaging") + implementation project(":matrix:matrix") implementation project(":matrix:matrix-http-ktor") implementation project(":matrix:services:auth") diff --git a/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt b/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt index 0590253..1d15604 100644 --- a/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt +++ b/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt @@ -1,7 +1,6 @@ package app.dapk.st import android.app.Application -import android.content.Intent import android.util.Log import app.dapk.st.core.CoreAndroidModule import app.dapk.st.core.ModuleProvider @@ -11,13 +10,13 @@ import app.dapk.st.core.extensions.ResettableUnsafeLazy import app.dapk.st.core.extensions.Scope import app.dapk.st.directory.DirectoryModule import app.dapk.st.domain.StoreModule +import app.dapk.st.firebase.messaging.MessagingModule import app.dapk.st.graph.AppModule import app.dapk.st.home.HomeModule import app.dapk.st.login.LoginModule import app.dapk.st.messenger.MessengerModule import app.dapk.st.notifications.NotificationsModule import app.dapk.st.profile.ProfileModule -import app.dapk.st.push.firebase.FirebasePushService import app.dapk.st.push.PushModule import app.dapk.st.settings.SettingsModule import app.dapk.st.share.ShareEntryModule @@ -75,6 +74,7 @@ class SmallTalkApplication : Application(), ModuleProvider { ProfileModule::class -> featureModules.profileModule NotificationsModule::class -> featureModules.notificationsModule PushModule::class -> featureModules.pushModule + MessagingModule::class -> featureModules.messagingModule MessengerModule::class -> featureModules.messengerModule TaskRunnerModule::class -> appModule.domainModules.taskRunnerModule CoreAndroidModule::class -> appModule.coreAndroidModule diff --git a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt index 24e0232..b5f35a3 100644 --- a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt +++ b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt @@ -16,6 +16,7 @@ import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.directory.DirectoryModule import app.dapk.st.domain.StoreModule +import app.dapk.st.firebase.messaging.MessagingModule import app.dapk.st.home.HomeModule import app.dapk.st.home.MainActivity import app.dapk.st.imageloader.ImageLoaderModule @@ -55,6 +56,7 @@ import app.dapk.st.olm.OlmPersistenceWrapper import app.dapk.st.olm.OlmWrapper import app.dapk.st.profile.ProfileModule import app.dapk.st.push.PushModule +import app.dapk.st.push.firebase.MessagingServiceAdapter import app.dapk.st.settings.SettingsModule import app.dapk.st.share.ShareEntryModule import app.dapk.st.tracking.TrackingModule @@ -208,6 +210,10 @@ internal class FeatureModules internal constructor( domainModules.pushModule } + val messagingModule by unsafeLazy { + domainModules.messaging + } + } internal class MatrixModules( @@ -428,23 +434,30 @@ internal class DomainModules( private val dispatchers: CoroutineDispatchers, ) { - val pushModule by unsafeLazy { + val pushHandler by unsafeLazy { val store = storeModule.value - val pushHandler = MatrixPushHandler( + MatrixPushHandler( workScheduler = workModule.workScheduler(), credentialsStore = store.credentialsStore(), matrixModules.sync, store.roomStore(), ) + } + + val messaging by unsafeLazy { MessagingModule(MessagingServiceAdapter(pushHandler), context) } + + val pushModule by unsafeLazy { PushModule( errorTracker, pushHandler, context, dispatchers, - SharedPreferencesDelegate(context.applicationContext, fileName = "dapk-user-preferences", dispatchers) + SharedPreferencesDelegate(context.applicationContext, fileName = "dapk-user-preferences", dispatchers), + messaging.messaging, ) } val taskRunnerModule by unsafeLazy { TaskRunnerModule(TaskRunnerAdapter(matrixModules.matrix::run, AppTaskRunner(matrixModules.push))) } + } internal class AndroidImageContentReader(private val contentResolver: ContentResolver) : ImageContentReader { diff --git a/build.gradle b/build.gradle index c28a7fb..004ac18 100644 --- a/build.gradle +++ b/build.gradle @@ -118,7 +118,7 @@ ext.applyAndroidLibraryModule = { project -> } ext.applyCrashlyticsIfRelease = { project -> - if (isReleaseBuild) { + if (isReleaseBuild && !isFoss()) { project.apply plugin: 'com.google.firebase.crashlytics' project.afterEvaluate { project.tasks.withType(com.google.firebase.crashlytics.buildtools.gradle.tasks.UploadMappingFileTask).configureEach { @@ -151,6 +151,19 @@ ext.androidImportFixturesWorkaround = { project, fixtures -> project.dependencies.testImplementation fixtures.files("build/libs/${fixtures.name}.jar") } +ext.isFoss = { + return rootProject.hasProperty("foss") +} + +ext.firebase = { dependencies, name -> + if (isFoss()) { + dependencies.implementation(project(":domains:firebase:$name-noop")) + } else { + dependencies.implementation(project(":domains:firebase:$name")) + } +} + + if (launchTask.contains("codeCoverageReport".toLowerCase())) { apply from: 'tools/coverage.gradle' -} \ No newline at end of file +} diff --git a/domains/android/push/build.gradle b/domains/android/push/build.gradle index dbcfe03..deafddc 100644 --- a/domains/android/push/build.gradle +++ b/domains/android/push/build.gradle @@ -6,8 +6,9 @@ dependencies { implementation project(':domains:android:core') implementation project(':domains:store') implementation project(':matrix:services:push') - implementation platform('com.google.firebase:firebase-bom:29.0.3') - implementation 'com.google.firebase:firebase-messaging' + + firebase(it, "messaging") + implementation Dependencies.mavenCentral.kotlinSerializationJson implementation Dependencies.jitPack.unifiedPush } diff --git a/domains/android/push/src/main/AndroidManifest.xml b/domains/android/push/src/main/AndroidManifest.xml index 61024b7..c308606 100644 --- a/domains/android/push/src/main/AndroidManifest.xml +++ b/domains/android/push/src/main/AndroidManifest.xml @@ -2,15 +2,6 @@ - - - - - - - diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt index 5b923c7..1333aff 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt @@ -7,6 +7,8 @@ import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.domain.Preferences import app.dapk.st.domain.push.PushTokenRegistrarPreferences +import app.dapk.st.firebase.messaging.Messaging +import app.dapk.st.firebase.messaging.MessagingModule import app.dapk.st.push.firebase.FirebasePushTokenRegistrar import app.dapk.st.push.unifiedpush.UnifiedPushRegistrar @@ -16,6 +18,7 @@ class PushModule( private val context: Context, private val dispatchers: CoroutineDispatchers, private val preferences: Preferences, + private val messaging: Messaging, ) : ProvidableModule { private val registrars by unsafeLazy { @@ -23,8 +26,8 @@ class PushModule( context, FirebasePushTokenRegistrar( errorTracker, - context, pushHandler, + messaging, ), UnifiedPushRegistrar(context), PushTokenRegistrarPreferences(preferences) diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebaseMessagingExtensions.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebaseMessagingExtensions.kt deleted file mode 100644 index 9ff0ac7..0000000 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebaseMessagingExtensions.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.dapk.st.push.firebase - -import com.google.firebase.messaging.FirebaseMessaging -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine - -suspend fun FirebaseMessaging.token() = suspendCoroutine { continuation -> - this.token.addOnCompleteListener { task -> - when { - task.isSuccessful -> continuation.resume(task.result!!) - task.isCanceled -> continuation.resumeWith(Result.failure(CancelledTokenFetchingException())) - else -> continuation.resumeWith(Result.failure(task.exception ?: UnknownTokenFetchingFailedException())) - } - } -} - -private class CancelledTokenFetchingException : Throwable() -private class UnknownTokenFetchingFailedException : Throwable() \ No newline at end of file diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt index 2c9321a..bd5a05b 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt @@ -1,37 +1,28 @@ package app.dapk.st.push.firebase -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.pm.PackageManager import app.dapk.st.core.AppLogTag import app.dapk.st.core.extensions.CrashScope import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.log +import app.dapk.st.firebase.messaging.Messaging import app.dapk.st.push.PushHandler import app.dapk.st.push.PushTokenPayload import app.dapk.st.push.PushTokenRegistrar -import app.dapk.st.push.unifiedpush.UnifiedPushMessageReceiver -import com.google.firebase.messaging.FirebaseMessaging private const val SYGNAL_GATEWAY = "https://sygnal.dapk.app/_matrix/push/v1/notify" class FirebasePushTokenRegistrar( override val errorTracker: ErrorTracker, - private val context: Context, private val pushHandler: PushHandler, + private val messaging: Messaging, ) : PushTokenRegistrar, CrashScope { override suspend fun registerCurrentToken() { log(AppLogTag.PUSH, "FCM - register current token") - context.packageManager.setComponentEnabledSetting( - ComponentName(context, FirebasePushService::class.java), - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, - PackageManager.DONT_KILL_APP, - ) + messaging.enable() kotlin.runCatching { - FirebaseMessaging.getInstance().token().also { + messaging.token().also { pushHandler.onNewToken( PushTokenPayload( token = it, @@ -48,14 +39,8 @@ class FirebasePushTokenRegistrar( override fun unregister() { log(AppLogTag.PUSH, "FCM - unregister") - FirebaseMessaging.getInstance().deleteToken() - context.stopService(Intent(context, FirebasePushService::class.java)) - - context.packageManager.setComponentEnabledSetting( - ComponentName(context, FirebasePushService::class.java), - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - PackageManager.DONT_KILL_APP, - ) + messaging.deleteToken() + messaging.disable() } } \ No newline at end of file diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushService.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/MessagingServiceAdapter.kt similarity index 54% rename from domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushService.kt rename to domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/MessagingServiceAdapter.kt index e1d79db..0bd2f0e 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushService.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/MessagingServiceAdapter.kt @@ -1,21 +1,18 @@ package app.dapk.st.push.firebase import app.dapk.st.core.AppLogTag -import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.core.log -import app.dapk.st.core.module +import app.dapk.st.firebase.messaging.ServiceDelegate import app.dapk.st.matrix.common.EventId import app.dapk.st.matrix.common.RoomId -import app.dapk.st.push.PushModule +import app.dapk.st.push.PushHandler import app.dapk.st.push.PushTokenPayload -import com.google.firebase.messaging.FirebaseMessagingService -import com.google.firebase.messaging.RemoteMessage private const val SYGNAL_GATEWAY = "https://sygnal.dapk.app/_matrix/push/v1/notify" -class FirebasePushService : FirebaseMessagingService() { - - private val handler by unsafeLazy { module().pushHandler() } +class MessagingServiceAdapter( + private val handler: PushHandler, +) : ServiceDelegate { override fun onNewToken(token: String) { log(AppLogTag.PUSH, "FCM onNewToken") @@ -27,10 +24,8 @@ class FirebasePushService : FirebaseMessagingService() { ) } - override fun onMessageReceived(message: RemoteMessage) { + override fun onMessageReceived(eventId: EventId?, roomId: RoomId?) { log(AppLogTag.PUSH, "FCM onMessage") - val eventId = message.data["event_id"]?.let { EventId(it) } - val roomId = message.data["room_id"]?.let { RoomId(it) } handler.onMessageReceived(eventId, roomId) } } diff --git a/domains/android/tracking/build.gradle b/domains/android/tracking/build.gradle index 8545a2f..25e3ca2 100644 --- a/domains/android/tracking/build.gradle +++ b/domains/android/tracking/build.gradle @@ -2,9 +2,5 @@ applyAndroidLibraryModule(project) dependencies { implementation project(':core') - implementation platform('com.google.firebase:firebase-bom:29.0.3') - implementation 'com.google.firebase:firebase-crashlytics' - - // is it worth the 400kb size increase? -// implementation 'com.google.firebase:firebase-analytics' + firebase(it, "crashlytics") } diff --git a/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/CrashlyticsCrashTracker.kt b/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/CrashTrackerLogger.kt similarity index 62% rename from domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/CrashlyticsCrashTracker.kt rename to domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/CrashTrackerLogger.kt index 158884a..cd2a99d 100644 --- a/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/CrashlyticsCrashTracker.kt +++ b/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/CrashTrackerLogger.kt @@ -4,16 +4,12 @@ import android.util.Log import app.dapk.st.core.AppLogTag import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.log -import com.google.firebase.crashlytics.FirebaseCrashlytics -class CrashlyticsCrashTracker( - private val firebaseCrashlytics: FirebaseCrashlytics, -) : ErrorTracker { +class CrashTrackerLogger : ErrorTracker { override fun track(throwable: Throwable, extra: String) { Log.e("ST", throwable.message, throwable) log(AppLogTag.ERROR_NON_FATAL, "${throwable.message ?: "N/A"} extra=$extra") - firebaseCrashlytics.recordException(throwable) } } diff --git a/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/TrackingModule.kt b/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/TrackingModule.kt index e097607..42642f4 100644 --- a/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/TrackingModule.kt +++ b/domains/android/tracking/src/main/kotlin/app/dapk/st/tracking/TrackingModule.kt @@ -1,9 +1,8 @@ package app.dapk.st.tracking -import android.util.Log import app.dapk.st.core.extensions.ErrorTracker import app.dapk.st.core.extensions.unsafeLazy -import com.google.firebase.crashlytics.FirebaseCrashlytics +import app.dapk.st.firebase.crashlytics.CrashlyticsModule class TrackingModule( private val isCrashTrackingEnabled: Boolean, @@ -11,13 +10,18 @@ class TrackingModule( val errorTracker: ErrorTracker by unsafeLazy { when (isCrashTrackingEnabled) { - true -> CrashlyticsCrashTracker(FirebaseCrashlytics.getInstance()) - false -> object : ErrorTracker { - override fun track(throwable: Throwable, extra: String) { - Log.e("error", throwable.message, throwable) - } - } + true -> compositeTracker( + CrashTrackerLogger(), + CrashlyticsModule().errorTracker, + ) + false -> CrashTrackerLogger() } } +} + +private fun compositeTracker(vararg loggers: ErrorTracker) = object : ErrorTracker { + override fun track(throwable: Throwable, extra: String) { + loggers.forEach { it.track(throwable, extra) } + } } \ No newline at end of file diff --git a/domains/firebase/crashlytics-noop/build.gradle b/domains/firebase/crashlytics-noop/build.gradle new file mode 100644 index 0000000..5ab1042 --- /dev/null +++ b/domains/firebase/crashlytics-noop/build.gradle @@ -0,0 +1,5 @@ +plugins { id 'kotlin' } + +dependencies { + implementation project(':core') +} diff --git a/domains/firebase/crashlytics-noop/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt b/domains/firebase/crashlytics-noop/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt new file mode 100644 index 0000000..0759d8e --- /dev/null +++ b/domains/firebase/crashlytics-noop/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt @@ -0,0 +1,16 @@ +package app.dapk.st.firebase.crashlytics + +import app.dapk.st.core.extensions.ErrorTracker +import app.dapk.st.core.extensions.unsafeLazy + +class CrashlyticsModule { + + val errorTracker: ErrorTracker by unsafeLazy { + object : ErrorTracker { + override fun track(throwable: Throwable, extra: String) { + // no op + } + } + } + +} \ No newline at end of file diff --git a/domains/firebase/crashlytics/build.gradle b/domains/firebase/crashlytics/build.gradle new file mode 100644 index 0000000..f502422 --- /dev/null +++ b/domains/firebase/crashlytics/build.gradle @@ -0,0 +1,7 @@ +applyAndroidLibraryModule(project) + +dependencies { + implementation project(':core') + implementation platform('com.google.firebase:firebase-bom:29.0.3') + implementation 'com.google.firebase:firebase-crashlytics' +} diff --git a/domains/firebase/crashlytics/src/main/AndroidManifest.xml b/domains/firebase/crashlytics/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1820009 --- /dev/null +++ b/domains/firebase/crashlytics/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsCrashTracker.kt b/domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsCrashTracker.kt new file mode 100644 index 0000000..3c634a2 --- /dev/null +++ b/domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsCrashTracker.kt @@ -0,0 +1,14 @@ +package app.dapk.st.firebase.crashlytics + +import app.dapk.st.core.extensions.ErrorTracker +import com.google.firebase.crashlytics.FirebaseCrashlytics + +class CrashlyticsCrashTracker( + private val firebaseCrashlytics: FirebaseCrashlytics, +) : ErrorTracker { + + override fun track(throwable: Throwable, extra: String) { + firebaseCrashlytics.recordException(throwable) + } +} + diff --git a/domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt b/domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt new file mode 100644 index 0000000..73db9b0 --- /dev/null +++ b/domains/firebase/crashlytics/src/main/kotlin/app/dapk/st/firebase/crashlytics/CrashlyticsModule.kt @@ -0,0 +1,13 @@ +package app.dapk.st.firebase.crashlytics + +import app.dapk.st.core.extensions.ErrorTracker +import app.dapk.st.core.extensions.unsafeLazy +import com.google.firebase.crashlytics.FirebaseCrashlytics + +class CrashlyticsModule { + + val errorTracker: ErrorTracker by unsafeLazy { + CrashlyticsCrashTracker(FirebaseCrashlytics.getInstance()) + } + +} \ No newline at end of file diff --git a/domains/firebase/messaging-noop/build.gradle b/domains/firebase/messaging-noop/build.gradle new file mode 100644 index 0000000..10bf518 --- /dev/null +++ b/domains/firebase/messaging-noop/build.gradle @@ -0,0 +1,6 @@ +applyAndroidLibraryModule(project) + +dependencies { + implementation project(':core') + implementation project(':matrix:common') +} diff --git a/domains/firebase/messaging-noop/src/main/AndroidManifest.xml b/domains/firebase/messaging-noop/src/main/AndroidManifest.xml new file mode 100644 index 0000000..15c2b55 --- /dev/null +++ b/domains/firebase/messaging-noop/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt new file mode 100644 index 0000000..160ae63 --- /dev/null +++ b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt @@ -0,0 +1,21 @@ +package app.dapk.st.firebase.messaging + +class Messaging { + + fun enable() { + // do nothing + } + + fun disable() { + // do nothing + } + + fun deleteToken() { + // do nothing + } + + suspend fun token(): String { + return "" + } + +} \ No newline at end of file diff --git a/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt new file mode 100644 index 0000000..c025ca5 --- /dev/null +++ b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt @@ -0,0 +1,17 @@ +package app.dapk.st.firebase.messaging + +import android.content.Context +import app.dapk.st.core.ProvidableModule +import app.dapk.st.core.extensions.unsafeLazy + +@Suppress("UNUSED") +class MessagingModule( + val serviceDelegate: ServiceDelegate, + val context: Context, +) : ProvidableModule { + + val messaging by unsafeLazy { + Messaging() + } + +} diff --git a/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt new file mode 100644 index 0000000..bbc6980 --- /dev/null +++ b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt @@ -0,0 +1,9 @@ +package app.dapk.st.firebase.messaging + +import app.dapk.st.matrix.common.EventId +import app.dapk.st.matrix.common.RoomId + +interface ServiceDelegate { + fun onNewToken(token: String) + fun onMessageReceived(eventId: EventId?, roomId: RoomId?) +} \ No newline at end of file diff --git a/domains/firebase/messaging/build.gradle b/domains/firebase/messaging/build.gradle new file mode 100644 index 0000000..6622273 --- /dev/null +++ b/domains/firebase/messaging/build.gradle @@ -0,0 +1,9 @@ +applyAndroidLibraryModule(project) + +dependencies { + implementation project(':core') + implementation project(':domains:android:core') + implementation project(':matrix:common') + implementation platform('com.google.firebase:firebase-bom:29.0.3') + implementation 'com.google.firebase:firebase-messaging' +} diff --git a/domains/firebase/messaging/src/main/AndroidManifest.xml b/domains/firebase/messaging/src/main/AndroidManifest.xml new file mode 100644 index 0000000..02ee9b7 --- /dev/null +++ b/domains/firebase/messaging/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/FirebasePushServiceDelegate.kt b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/FirebasePushServiceDelegate.kt new file mode 100644 index 0000000..6d99b03 --- /dev/null +++ b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/FirebasePushServiceDelegate.kt @@ -0,0 +1,26 @@ +package app.dapk.st.firebase.messaging + +import app.dapk.st.core.AppLogTag +import app.dapk.st.core.extensions.unsafeLazy +import app.dapk.st.core.log +import app.dapk.st.core.module +import app.dapk.st.matrix.common.EventId +import app.dapk.st.matrix.common.RoomId +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage + +class FirebasePushServiceDelegate : FirebaseMessagingService() { + + private val delegate by unsafeLazy { module().serviceDelegate } + + override fun onNewToken(token: String) { + delegate.onNewToken(token) + } + + override fun onMessageReceived(message: RemoteMessage) { + log(AppLogTag.PUSH, "FCM onMessage") + val eventId = message.data["event_id"]?.let { EventId(it) } + val roomId = message.data["room_id"]?.let { RoomId(it) } + delegate.onMessageReceived(eventId, roomId) + } +} diff --git a/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt new file mode 100644 index 0000000..dc8dadd --- /dev/null +++ b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt @@ -0,0 +1,50 @@ +package app.dapk.st.firebase.messaging + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import com.google.firebase.messaging.FirebaseMessaging +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +class Messaging( + private val instance: FirebaseMessaging, + private val context: Context, +) { + + fun enable() { + context.packageManager.setComponentEnabledSetting( + ComponentName(context, FirebasePushServiceDelegate::class.java), + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP, + ) + } + + fun disable() { + context.stopService(Intent(context, FirebasePushServiceDelegate::class.java)) + context.packageManager.setComponentEnabledSetting( + ComponentName(context, FirebasePushServiceDelegate::class.java), + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP, + ) + + } + + fun deleteToken() { + instance.deleteToken() + } + + suspend fun token() = suspendCoroutine { continuation -> + instance.token.addOnCompleteListener { task -> + when { + task.isSuccessful -> continuation.resume(task.result!!) + task.isCanceled -> continuation.resumeWith(Result.failure(CancelledTokenFetchingException())) + else -> continuation.resumeWith(Result.failure(task.exception ?: UnknownTokenFetchingFailedException())) + } + } + } + + private class CancelledTokenFetchingException : Throwable() + private class UnknownTokenFetchingFailedException : Throwable() +} \ No newline at end of file diff --git a/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt new file mode 100644 index 0000000..e0bb5ef --- /dev/null +++ b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/MessagingModule.kt @@ -0,0 +1,17 @@ +package app.dapk.st.firebase.messaging + +import android.content.Context +import app.dapk.st.core.ProvidableModule +import app.dapk.st.core.extensions.unsafeLazy +import com.google.firebase.messaging.FirebaseMessaging + +class MessagingModule( + val serviceDelegate: ServiceDelegate, + val context: Context, +) : ProvidableModule { + + val messaging by unsafeLazy { + Messaging(FirebaseMessaging.getInstance(), context) + } + +} diff --git a/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt new file mode 100644 index 0000000..bbc6980 --- /dev/null +++ b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/ServiceDelegate.kt @@ -0,0 +1,9 @@ +package app.dapk.st.firebase.messaging + +import app.dapk.st.matrix.common.EventId +import app.dapk.st.matrix.common.RoomId + +interface ServiceDelegate { + fun onNewToken(token: String) + fun onMessageReceived(eventId: EventId?, roomId: RoomId?) +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index d457b3a..4b8bbf4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -34,6 +34,11 @@ include ':domains:store' include ':domains:olm-stub' include ':domains:olm' +include ':domains:firebase:crashlytics' +include ':domains:firebase:crashlytics-noop' +include ':domains:firebase:messaging' +include ':domains:firebase:messaging-noop' + include ':matrix:matrix' include ':matrix:common' include ':matrix:matrix-http' From 477ac52d16e97004681a86d2e77afe827ff6d9eb Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 31 Aug 2022 17:52:39 +0100 Subject: [PATCH 08/13] checking for firebase inclusion or play services availability and removing FCM option if it's missing --- .../kotlin/app/dapk/st/graph/AppModule.kt | 2 +- .../kotlin/app/dapk/st/push/PushModule.kt | 5 ++-- .../app/dapk/st/push/PushTokenRegistrars.kt | 29 ++++++++++++------- .../MessagingPushTokenRegistrar.kt} | 6 ++-- .../MessagingServiceAdapter.kt | 2 +- .../dapk/st/firebase/messaging/Messaging.kt | 2 ++ .../dapk/st/firebase/messaging/Messaging.kt | 4 +++ 7 files changed, 33 insertions(+), 17 deletions(-) rename domains/android/push/src/main/kotlin/app/dapk/st/push/{firebase/FirebasePushTokenRegistrar.kt => messaging/MessagingPushTokenRegistrar.kt} (91%) rename domains/android/push/src/main/kotlin/app/dapk/st/push/{firebase => messaging}/MessagingServiceAdapter.kt (96%) diff --git a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt index b5f35a3..8f20819 100644 --- a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt +++ b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt @@ -56,7 +56,7 @@ import app.dapk.st.olm.OlmPersistenceWrapper import app.dapk.st.olm.OlmWrapper import app.dapk.st.profile.ProfileModule import app.dapk.st.push.PushModule -import app.dapk.st.push.firebase.MessagingServiceAdapter +import app.dapk.st.push.messaging.MessagingServiceAdapter import app.dapk.st.settings.SettingsModule import app.dapk.st.share.ShareEntryModule import app.dapk.st.tracking.TrackingModule diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt index 1333aff..dc8c77e 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/PushModule.kt @@ -8,8 +8,7 @@ import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.domain.Preferences import app.dapk.st.domain.push.PushTokenRegistrarPreferences import app.dapk.st.firebase.messaging.Messaging -import app.dapk.st.firebase.messaging.MessagingModule -import app.dapk.st.push.firebase.FirebasePushTokenRegistrar +import app.dapk.st.push.messaging.MessagingPushTokenRegistrar import app.dapk.st.push.unifiedpush.UnifiedPushRegistrar class PushModule( @@ -24,7 +23,7 @@ class PushModule( private val registrars by unsafeLazy { PushTokenRegistrars( context, - FirebasePushTokenRegistrar( + MessagingPushTokenRegistrar( errorTracker, pushHandler, messaging, diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/PushTokenRegistrars.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/PushTokenRegistrars.kt index 7ce0658..44a9679 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/PushTokenRegistrars.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/PushTokenRegistrars.kt @@ -2,7 +2,7 @@ package app.dapk.st.push import android.content.Context import app.dapk.st.domain.push.PushTokenRegistrarPreferences -import app.dapk.st.push.firebase.FirebasePushTokenRegistrar +import app.dapk.st.push.messaging.MessagingPushTokenRegistrar import app.dapk.st.push.unifiedpush.UnifiedPushRegistrar import org.unifiedpush.android.connector.UnifiedPush @@ -11,7 +11,7 @@ private val NONE = Registrar("None") class PushTokenRegistrars( private val context: Context, - private val firebasePushTokenRegistrar: FirebasePushTokenRegistrar, + private val messagingPushTokenRegistrar: MessagingPushTokenRegistrar, private val unifiedPushRegistrar: UnifiedPushRegistrar, private val pushTokenStore: PushTokenRegistrarPreferences, ) : PushTokenRegistrar { @@ -19,27 +19,36 @@ class PushTokenRegistrars( private var selection: Registrar? = null fun options(): List { - return listOf(NONE, FIREBASE_OPTION) + UnifiedPush.getDistributors(context).map { Registrar(it) } + val messagingOption = when (messagingPushTokenRegistrar.isAvailable()) { + true -> FIREBASE_OPTION + else -> null + } + return listOfNotNull(NONE, messagingOption) + UnifiedPush.getDistributors(context).map { Registrar(it) } } - suspend fun currentSelection() = selection ?: (pushTokenStore.currentSelection()?.let { Registrar(it) } ?: FIREBASE_OPTION).also { selection = it } + suspend fun currentSelection() = selection ?: (pushTokenStore.currentSelection()?.let { Registrar(it) } ?: defaultSelection()).also { selection = it } + + private fun defaultSelection() = when (messagingPushTokenRegistrar.isAvailable()) { + true -> FIREBASE_OPTION + else -> NONE + } suspend fun makeSelection(option: Registrar) { selection = option pushTokenStore.store(option.id) when (option) { NONE -> { - firebasePushTokenRegistrar.unregister() + messagingPushTokenRegistrar.unregister() unifiedPushRegistrar.unregister() } FIREBASE_OPTION -> { unifiedPushRegistrar.unregister() - firebasePushTokenRegistrar.registerCurrentToken() + messagingPushTokenRegistrar.registerCurrentToken() } else -> { - firebasePushTokenRegistrar.unregister() + messagingPushTokenRegistrar.unregister() unifiedPushRegistrar.registerSelection(option) } } @@ -47,7 +56,7 @@ class PushTokenRegistrars( override suspend fun registerCurrentToken() { when (selection) { - FIREBASE_OPTION -> firebasePushTokenRegistrar.registerCurrentToken() + FIREBASE_OPTION -> messagingPushTokenRegistrar.registerCurrentToken() NONE -> { // do nothing } @@ -58,10 +67,10 @@ class PushTokenRegistrars( override fun unregister() { when (selection) { - FIREBASE_OPTION -> firebasePushTokenRegistrar.unregister() + FIREBASE_OPTION -> messagingPushTokenRegistrar.unregister() NONE -> { runCatching { - firebasePushTokenRegistrar.unregister() + messagingPushTokenRegistrar.unregister() unifiedPushRegistrar.unregister() } } diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/messaging/MessagingPushTokenRegistrar.kt similarity index 91% rename from domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt rename to domains/android/push/src/main/kotlin/app/dapk/st/push/messaging/MessagingPushTokenRegistrar.kt index bd5a05b..760c313 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/FirebasePushTokenRegistrar.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/messaging/MessagingPushTokenRegistrar.kt @@ -1,4 +1,4 @@ -package app.dapk.st.push.firebase +package app.dapk.st.push.messaging import app.dapk.st.core.AppLogTag import app.dapk.st.core.extensions.CrashScope @@ -11,7 +11,7 @@ import app.dapk.st.push.PushTokenRegistrar private const val SYGNAL_GATEWAY = "https://sygnal.dapk.app/_matrix/push/v1/notify" -class FirebasePushTokenRegistrar( +class MessagingPushTokenRegistrar( override val errorTracker: ErrorTracker, private val pushHandler: PushHandler, private val messaging: Messaging, @@ -43,4 +43,6 @@ class FirebasePushTokenRegistrar( messaging.disable() } + fun isAvailable() = messaging.isAvailable() + } \ No newline at end of file diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/MessagingServiceAdapter.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/messaging/MessagingServiceAdapter.kt similarity index 96% rename from domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/MessagingServiceAdapter.kt rename to domains/android/push/src/main/kotlin/app/dapk/st/push/messaging/MessagingServiceAdapter.kt index 0bd2f0e..cceed3d 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/firebase/MessagingServiceAdapter.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/messaging/MessagingServiceAdapter.kt @@ -1,4 +1,4 @@ -package app.dapk.st.push.firebase +package app.dapk.st.push.messaging import app.dapk.st.core.AppLogTag import app.dapk.st.core.log diff --git a/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt index 160ae63..aea7843 100644 --- a/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt +++ b/domains/firebase/messaging-noop/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt @@ -2,6 +2,8 @@ package app.dapk.st.firebase.messaging class Messaging { + fun isAvailable() = false + fun enable() { // do nothing } diff --git a/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt index dc8dadd..5852c4d 100644 --- a/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt +++ b/domains/firebase/messaging/src/main/kotlin/app/dapk/st/firebase/messaging/Messaging.kt @@ -4,6 +4,8 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.PackageManager +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailabilityLight import com.google.firebase.messaging.FirebaseMessaging import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -13,6 +15,8 @@ class Messaging( private val context: Context, ) { + fun isAvailable() = GoogleApiAvailabilityLight.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS + fun enable() { context.packageManager.setComponentEnabledSetting( ComponentName(context, FirebasePushServiceDelegate::class.java), From e1b1e77b833f1bfa11525f7dee5e9948f7231ede Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 31 Aug 2022 18:14:47 +0100 Subject: [PATCH 09/13] skipping noop modules from the coverage report --- tools/coverage.gradle | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/tools/coverage.gradle b/tools/coverage.gradle index 15d22bd..009e835 100644 --- a/tools/coverage.gradle +++ b/tools/coverage.gradle @@ -67,30 +67,10 @@ def collectProjects(predicate) { return subprojects.findAll { it.buildFile.isFile() && predicate(it) } } -//task unitCodeCoverageReport(type: JacocoReport) { -// outputs.upToDateWhen { false } -// rootProject.apply plugin: 'jacoco' -// def excludedProjects = [ -// 'olm-stub', -// 'test-harness' -// ] -// def projects = collectProjects { !excludedProjects.contains(it.name) } -// dependsOn { ["app:assembleDebug"] + projects*.test } -// initializeReport(it, projects, excludes) -//} -// -//task harnessCodeCoverageReport(type: JacocoReport) { -// outputs.upToDateWhen { false } -// rootProject.apply plugin: 'jacoco' -// def projects = collectProjects { true } -// dependsOn { ["app:assembleDebug", project(":test-harness").test] } -// initializeReport(it, projects, excludes) -//} - task allCodeCoverageReport(type: JacocoReport) { outputs.upToDateWhen { false } rootProject.apply plugin: 'jacoco' - def projects = collectProjects { !it.name.contains("stub") } + def projects = collectProjects { !it.name.contains("stub") && !it.name.contains("-noop") } dependsOn { ["app:assembleDebug"] + projects*.test } initializeReport(it, projects, excludes) } From 21eff5a4abb80e904c531f0ed0db2e1da2732d36 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 31 Aug 2022 18:22:21 +0100 Subject: [PATCH 10/13] compiling foss app as part of the assemble pipeline --- .github/workflows/assemble.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/assemble.yml b/.github/workflows/assemble.yml index 5dc3d99..ed0cc2a 100644 --- a/.github/workflows/assemble.yml +++ b/.github/workflows/assemble.yml @@ -24,4 +24,6 @@ jobs: - uses: gradle/gradle-build-action@v2 - name: Assemble debug variant - run: ./gradlew assembleDebug --no-daemon + run: | + ./gradlew assembleDebug --no-daemon + ./gradlew assembleDebug -Pfoss --no-daemon From 31f7f93ad1ad4efa4fd9ed9f9b94f073cea78996 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 31 Aug 2022 19:10:26 +0100 Subject: [PATCH 11/13] Adding build commands - adds mention of foss variant --- README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b94975e..cb587b2 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@ - Focused on reliability and stability. - Bare-bones feature set. -##### _*Google play only with automatic crash reporting enabled_ - --- ### Feature list @@ -28,7 +26,8 @@ - Message bubbles, supporting text, replies and edits - Push notifications (DMs always notify, Rooms notify once) - Importing of E2E room keys from Element clients -- [UnifiedPush](https://unifiedpush.org/) +- [UnifiedPush](https://unifiedpush.org/) +- FOSS variant ### Planned @@ -57,4 +56,34 @@ --- + +### Building + + +##### Debug `.apk` + +```bash +./gradlew assembleDebug +``` + +##### Release (signed with debug key) `.apk` + +```bash +./gradlew assembleRelease +``` + +##### Unsigned release `.apk` + +```bash +./gradlew assembleRelease -Punsigned +``` + +##### Unsigned release (FOSS) `.apk` + +```bash +./gradlew assembleRelease -Punsigned -Pfoss +``` + +--- + #### Join the conversation @ https://matrix.to/#/#small-talk:iswell.cool From abe7208f273d305aa140fdcb6eedfa0f722af758 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 31 Aug 2022 20:34:40 +0100 Subject: [PATCH 12/13] renaming foss output to avoid conflicts --- app/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 3f862b6..0c81f66 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,10 @@ android { } else { resConfigs "en" } + + if (isFoss()) { + archivesBaseName = "$archivesBaseName-foss" + } } bundle { From 3eac935ac88006916cae3f49aec8ee17265662ea Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 31 Aug 2022 19:39:04 +0000 Subject: [PATCH 13/13] updating version for release --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index a85baed..60997cb 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { "name": "0.0.1-alpha04", - "code": 6 + "code": 7 } \ No newline at end of file