Merge branch 'hotfix/nologin'
Some checks failed
Push (master) / Build for Google Play (AAB) (push) Failing after 1s

This commit is contained in:
Kuba Szczodrzyński 2024-07-08 14:39:02 +02:00
commit f2a20c3aae
No known key found for this signature in database
GPG Key ID: 43037AC62A600562
31 changed files with 479 additions and 522 deletions

View File

@ -23,8 +23,6 @@ def get_password(
auth_plugin="mysql_native_password",
)
print(f"Generating passwords for version {version_name} ({version_code})")
password = base64.b64encode(secrets.token_bytes(16)).decode()
iv = secrets.token_bytes(16)

View File

@ -102,7 +102,9 @@ def get_commit_log(project_dir: str, format: str, max_lines: int = None) -> str:
)
log = subprocess.run(
args=f"git log {last_tag}..HEAD --format=%an%x00%at%x00%h%x00%s%x00%D".split(" "),
args=f"git log {last_tag}..HEAD --format=%an%x00%at%x00%h%x00%s%x00%D".split(
" "
),
cwd=project_dir,
stdout=subprocess.PIPE,
)

View File

@ -1,11 +1,8 @@
import json
import os
import re
import sys
from datetime import datetime, timedelta
import requests
from _utils import (
get_commit_log,
get_project_dir,
@ -25,17 +22,6 @@ if __name__ == "__main__":
print("Missing GitHub environment variables.")
exit(-1)
with requests.get(
f"https://api.github.com/repos/{repo}/actions/runs?per_page=5&status=success"
) as r:
data = json.loads(r.text)
runs = [run for run in data["workflow_runs"] if run["head_sha"] == sha]
if runs:
print("::set-output name=hasNewChanges::false")
exit(0)
print("::set-output name=hasNewChanges::true")
project_dir = get_project_dir()
(version_code, version_name) = read_gradle_version(project_dir)
@ -48,8 +34,8 @@ if __name__ == "__main__":
date -= timedelta(days=1)
version_name += "+nightly." + date.strftime("%Y%m%d")
print("::set-output name=appVersionName::" + version_name)
print("::set-output name=appVersionCode::" + str(version_code))
print("appVersionName=" + version_name)
print("appVersionCode=" + str(version_code))
write_gradle_version(project_dir, version_code, version_name)

23
.github/utils/check_nightly.py vendored Normal file
View File

@ -0,0 +1,23 @@
import json
import os
import requests
if __name__ == "__main__":
repo = os.getenv("GITHUB_REPOSITORY")
sha = os.getenv("GITHUB_SHA")
if not repo or not sha:
print("Missing GitHub environment variables.")
exit(-1)
with requests.get(
f"https://api.github.com/repos/{repo}/actions/runs?per_page=5&status=success"
) as r:
data = json.loads(r.text)
runs = [run for run in data["workflow_runs"] if run["head_sha"] == sha]
if runs:
print("hasNewChanges=false")
exit(0)
print("hasNewChanges=true")

View File

@ -12,13 +12,13 @@ if __name__ == "__main__":
(version_code, version_name) = read_gradle_version(project_dir)
print("::set-output name=appVersionName::" + version_name)
print("::set-output name=appVersionCode::" + str(version_code))
print("appVersionName=" + version_name)
print("appVersionCode=" + str(version_code))
dir = f"{project_dir}/app/release/whatsnew-{version_name}/"
os.makedirs(dir, exist_ok=True)
print("::set-output name=changelogDir::" + dir)
print("changelogDir=" + dir)
(title, changelog) = get_changelog(project_dir, format="plain")
@ -27,9 +27,9 @@ if __name__ == "__main__":
f.write(title)
f.write("\n")
f.write(changelog)
print("::set-output name=changelogPlainTitledFile::" + dir + "whatsnew_titled.txt")
print("changelogPlainTitledFile=" + dir + "whatsnew_titled.txt")
print("::set-output name=changelogTitle::" + title)
print("changelogTitle=" + title)
# plain text changelog, max 500 chars - Google Play
with open(dir + "whatsnew-pl-PL", "w", encoding="utf-8") as f:
@ -41,32 +41,31 @@ if __name__ == "__main__":
changelog = changelog.strip()
f.write(changelog)
print("::set-output name=changelogPlainFile::" + dir + "whatsnew-pl-PL")
print("changelogPlainFile=" + dir + "whatsnew-pl-PL")
# markdown changelog - Discord webhook
(_, changelog) = get_changelog(project_dir, format="markdown")
with open(dir + "whatsnew.md", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogMarkdownFile::" + dir + "whatsnew.md")
print("changelogMarkdownFile=" + dir + "whatsnew.md")
# html changelog - version info in DB
(_, changelog) = get_changelog(project_dir, format="html")
with open(dir + "whatsnew.html", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogHtmlFile::" + dir + "whatsnew.html")
print("changelogHtmlFile=" + dir + "whatsnew.html")
changelog = get_commit_log(project_dir, format="plain", max_lines=10)
with open(dir + "commit_log.txt", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=commitLogPlainFile::" + dir + "commit_log.txt")
print("commitLogPlainFile=" + dir + "commit_log.txt")
changelog = get_commit_log(project_dir, format="markdown", max_lines=10)
with open(dir + "commit_log.md", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=commitLogMarkdownFile::" + dir + "commit_log.md")
print("commitLogMarkdownFile=" + dir + "commit_log.md")
changelog = get_commit_log(project_dir, format="html", max_lines=10)
with open(dir + "commit_log.html", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=commitLogHtmlFile::" + dir + "commit_log.html")
print("commitLogHtmlFile=" + dir + "commit_log.html")

View File

@ -13,7 +13,7 @@ if __name__ == "__main__":
files = glob.glob(f"{project_dir}/app/release/*.*")
for file in files:
file_relative = file.replace(os.getenv("GITHUB_WORKSPACE") + "/", "")
file_relative = file.replace(project_dir + "/", "")
if "-aligned.apk" in file:
os.unlink(file)
elif "-signed.apk" in file:
@ -22,5 +22,5 @@ if __name__ == "__main__":
os.unlink(new_file)
os.rename(file, new_file)
elif ".apk" in file or ".aab" in file:
print("::set-output name=signedReleaseFile::" + file)
print("::set-output name=signedReleaseFileRelative::" + file_relative)
print("signedReleaseFile=" + file)
print("signedReleaseFileRelative=" + file_relative)

View File

@ -64,7 +64,14 @@ def save_version(
if build_type in ["nightly", "daily"]:
download_url = apk_server_nightly + apk_name if apk_name else None
else:
download_url = apk_server_release + apk_name if apk_name else None
# download_url = apk_server_release + apk_name if apk_name else None
download_url = (
f"https://github.com/szkolny-eu/szkolny-android/releases/download/v{version_name}/{apk_name}"
if apk_name
else None
)
if download_url:
print("downloadUrl=" + download_url)
cols = [
"versionCode",
@ -119,4 +126,12 @@ if __name__ == "__main__":
APK_SERVER_RELEASE = os.getenv("APK_SERVER_RELEASE")
APK_SERVER_NIGHTLY = os.getenv("APK_SERVER_NIGHTLY")
save_version(project_dir, DB_HOST, DB_USER, DB_PASS, DB_NAME, APK_SERVER_RELEASE, APK_SERVER_NIGHTLY)
save_version(
project_dir,
DB_HOST,
DB_USER,
DB_PASS,
DB_NAME,
APK_SERVER_RELEASE,
APK_SERVER_NIGHTLY,
)

View File

@ -31,8 +31,6 @@ def sign(
SIGNING_FORMAT = "$param1.{}.$param2"
CPP_FORMAT = "/*{}*/\nstatic toys AES_IV[16] = {{\n\t{} }};"
print(f"Writing passwords for version {version_name} ({version_code})")
iv_hex = " ".join(["{:02x}".format(x) for x in iv])
iv_cpp = ", ".join(["0x{:02x}".format(x) for x in iv])
@ -71,8 +69,8 @@ if __name__ == "__main__":
version_name, version_code, DB_HOST, DB_USER, DB_PASS, DB_NAME
)
print("::set-output name=appVersionName::" + version_name)
print("::set-output name=appVersionCode::" + str(version_code))
print("appVersionName=" + version_name)
print("appVersionCode=" + str(version_code))
sign(
project_dir,

View File

@ -11,8 +11,7 @@ from _utils import get_changelog, get_commit_log, get_project_dir, read_gradle_v
def post_webhook(
project_dir: str,
apk_file: str,
apk_server_release: str,
apk_server_nightly: str,
download_url: str,
webhook_release: str,
webhook_testing: str,
):
@ -25,12 +24,6 @@ def post_webhook(
testing = ["dev", "beta", "nightly", "daily"]
testing = build_type in testing
apk_name = os.path.basename(apk_file)
if build_type in ["nightly", "daily"]:
download_url = apk_server_nightly + apk_name
else:
download_url = apk_server_release + apk_name
if testing:
build_date = int(os.stat(apk_file).st_mtime)
if build_date:
@ -48,13 +41,17 @@ def post_webhook(
requests.post(url=webhook_testing, json=webhook)
else:
changelog = get_changelog(project_dir, format="markdown")
webhook = get_webhook_release(changelog, download_url)
webhook = get_webhook_release(version_name, changelog, download_url)
requests.post(url=webhook_release, json=webhook)
def get_webhook_release(changelog: str, download_url: str):
def get_webhook_release(version_name: str, changelog: str, download_url: str):
(title, content) = changelog
return {"content": f"__**{title}**__\n{content}\n{download_url}"}
return {
"content": (
f"__**{title}**__\n{content}\n[Szkolny.eu {version_name}]({download_url})"
),
}
def get_webhook_testing(
@ -73,9 +70,11 @@ def get_webhook_testing(
"fields": [
{
"name": f"Wersja `{version_name}`",
"value": f"[Pobierz .APK]({download_url})"
if download_url
else "*Pobieranie niedostępne*",
"value": (
f"[Pobierz .APK]({download_url})"
if download_url
else "*Pobieranie niedostępne*"
),
"inline": False,
},
{
@ -103,16 +102,14 @@ if __name__ == "__main__":
load_dotenv()
APK_FILE = os.getenv("APK_FILE")
APK_SERVER_RELEASE = os.getenv("APK_SERVER_RELEASE")
APK_SERVER_NIGHTLY = os.getenv("APK_SERVER_NIGHTLY")
DOWNLOAD_URL = os.getenv("DOWNLOAD_URL")
WEBHOOK_RELEASE = os.getenv("WEBHOOK_RELEASE")
WEBHOOK_TESTING = os.getenv("WEBHOOK_TESTING")
post_webhook(
project_dir,
APK_FILE,
APK_SERVER_RELEASE,
APK_SERVER_NIGHTLY,
DOWNLOAD_URL,
WEBHOOK_RELEASE,
WEBHOOK_TESTING,
)

195
.github/workflows/_build.yml vendored Normal file
View File

@ -0,0 +1,195 @@
name: "[reusable] Szkolny.eu Build"
on:
workflow_call:
inputs:
nightly:
type: boolean
default: false
build-apk:
type: boolean
default: false
build-aab:
type: boolean
default: false
release-ssh:
type: boolean
default: false
release-github:
type: boolean
default: false
release-firebase:
type: boolean
default: false
release-google-play:
type: boolean
default: false
release-discord:
type: boolean
default: false
secrets:
APK_SERVER_NIGHTLY:
APK_SERVER_RELEASE:
DB_HOST:
DB_NAME:
DB_PASS:
DB_USER:
FIREBASE_APP_ID:
FIREBASE_GROUPS_NIGHTLY:
FIREBASE_GROUPS_RELEASE:
FIREBASE_SERVICE_ACCOUNT_JSON:
KEY_ALIAS_PASSWORD:
KEY_ALIAS:
KEY_STORE_PASSWORD:
KEY_STORE:
PLAY_RELEASE_TRACK:
PLAY_SERVICE_ACCOUNT_JSON:
SSH_IP:
SSH_KEY:
SSH_PATH_NIGHTLY:
SSH_PATH_RELEASE:
SSH_USERNAME:
WEBHOOK_RELEASE:
WEBHOOK_TESTING:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
clean: false
- name: Setup JDK 17
uses: actions/setup-java@v3
with:
distribution: "temurin"
java-version: "17"
- name: Setup Python
uses: actions/setup-python@v4
- name: Install Python packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Bump nightly version
if: ${{ inputs.nightly }}
run: python $GITHUB_WORKSPACE/.github/utils/bump_nightly.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Write signing passwords and keystore
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
KEY_STORE: ${{ secrets.KEY_STORE }}
run: |
python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit >> $GITHUB_OUTPUT
echo $KEY_STORE | base64 --decode > keystore.jks
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Build app with Gradle
if: ${{ inputs.build-apk || inputs.build-aab }}
run: |
chmod +x ./gradlew
./gradlew \
${{ inputs.build-apk && 'assembleOfficialRelease' || '' }} \
${{ inputs.build-aab && 'bundlePlayRelease' || '' }} \
-P android.injected.signing.store.file=${{ github.workspace }}/keystore.jks \
-P android.injected.signing.store.password=${{ secrets.KEY_STORE_PASSWORD }} \
-P android.injected.signing.key.alias=${{ secrets.KEY_ALIAS }} \
-P android.injected.signing.key.password=${{ secrets.KEY_ALIAS_PASSWORD }}
- name: Upload release to server
if: ${{ inputs.release-ssh }}
uses: easingthemes/ssh-deploy@v2.1.6
env:
REMOTE_HOST: ${{ secrets.SSH_IP }}
REMOTE_USER: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: app/release/
TARGET: ${{ inputs.nightly && secrets.SSH_PATH_NIGHTLY || secrets.SSH_PATH_RELEASE }}
- name: Find signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/find_artifacts.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Extract release changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Save version to database
id: save
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Release on GitHub
if: ${{ inputs.release-github }}
uses: softprops/action-gh-release@v1
with:
name: ${{ steps.changelog.outputs.changelogTitle }}
body_path: ${{ steps.changelog.outputs.changelogMarkdownFile }}
files: ${{ steps.artifacts.outputs.signedReleaseFile }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Distribute to App Distribution
if: ${{ inputs.release-firebase }}
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_JSON }}
file: ${{ steps.artifacts.outputs.signedReleaseFile }}
groups: ${{ inputs.nightly && secrets.FIREBASE_GROUPS_NIGHTLY || secrets.FIREBASE_GROUPS_RELEASE }}
releaseNotesFile: ${{ inputs.nightly && steps.changelog.outputs.commitLogPlainFile || steps.changelog.outputs.changelogPlainTitledFile }}
- name: Publish AAB to Google Play
if: ${{ inputs.release-google-play }}
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
packageName: pl.szczodrzynski.edziennik
releaseFiles: ${{ steps.artifacts.outputs.signedReleaseFile }}
releaseName: ${{ steps.changelog.outputs.appVersionName }}
track: ${{ secrets.PLAY_RELEASE_TRACK }}
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
status: completed
- name: Post Discord webhook
if: ${{ inputs.release-discord }}
env:
APK_FILE: ${{ steps.artifacts.outputs.signedReleaseFile }}
DOWNLOAD_URL: ${{ steps.save.outputs.downloadUrl }}
WEBHOOK_RELEASE: ${{ secrets.WEBHOOK_RELEASE }}
WEBHOOK_TESTING: ${{ secrets.WEBHOOK_TESTING }}
run: python $GITHUB_WORKSPACE/.github/utils/webhook_discord.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: always()
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

View File

@ -1,154 +0,0 @@
name: Nightly build
on:
schedule:
# 23:30 UTC, 0:30 or 1:30 CET/CEST
- cron: "30 23 * * *"
workflow_dispatch:
jobs:
prepare:
name: Prepare build environment
runs-on: self-hosted
outputs:
hasNewChanges: ${{ steps.nightly.outputs.hasNewChanges }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
clean: false
- name: Set executable permissions to gradlew
run: chmod +x ./gradlew
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Bump nightly version
id: nightly
run: python $GITHUB_WORKSPACE/.github/utils/bump_nightly.py $GITHUB_WORKSPACE
- name: Write signing passwords
if: steps.nightly.outputs.hasNewChanges
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
run: python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit
build:
name: Build APK
runs-on: self-hosted
needs:
- prepare
if: ${{ needs.prepare.outputs.hasNewChanges == 'true' }}
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Assemble official release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: assembleOfficialRelease
sign:
name: Sign APK
runs-on: self-hosted
needs:
- build
outputs:
signedReleaseFile: ${{ steps.artifacts.outputs.signedReleaseFile }}
signedReleaseFileRelative: ${{ steps.artifacts.outputs.signedReleaseFileRelative }}
steps:
- name: Sign build artifacts
id: sign_app
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/release
signingKeyBase64: ${{ secrets.KEY_STORE }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_ALIAS_PASSWORD }}
env:
ANDROID_HOME: ${{ needs.build.outputs.androidHome }}
ANDROID_SDK_ROOT: ${{ needs.build.outputs.androidSdkRoot }}
BUILD_TOOLS_VERSION: "30.0.2"
- name: Rename signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/rename_artifacts.py $GITHUB_WORKSPACE
publish:
name: Publish APK
runs-on: self-hosted
needs:
- sign
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Extract changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE
- name: Upload APK to SFTP
uses: easingthemes/ssh-deploy@v2.1.6
env:
REMOTE_HOST: ${{ secrets.SSH_IP }}
REMOTE_USER: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: ${{ needs.sign.outputs.signedReleaseFileRelative }}
TARGET: ${{ secrets.SSH_PATH_NIGHTLY }}
- name: Save version metadata
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE
- name: Distribute to App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: ${{ secrets.FIREBASE_GROUPS_NIGHTLY }}
file: ${{ needs.sign.outputs.signedReleaseFile }}
releaseNotesFile: ${{ steps.changelog.outputs.commitLogPlainFile }}
- name: Post Discord webhook
env:
APK_FILE: ${{ needs.sign.outputs.signedReleaseFile }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
WEBHOOK_RELEASE: ${{ secrets.WEBHOOK_RELEASE }}
WEBHOOK_TESTING: ${{ secrets.WEBHOOK_TESTING }}
run: python $GITHUB_WORKSPACE/.github/utils/webhook_discord.py $GITHUB_WORKSPACE
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: true
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

View File

@ -1,132 +0,0 @@
name: Release build - Google Play [AAB]
on:
push:
branches:
- "master"
jobs:
prepare:
name: Prepare build environment
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
clean: false
- name: Set executable permissions to gradlew
run: chmod +x ./gradlew
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Write signing passwords
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
run: python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit
build:
name: Build App Bundle
runs-on: self-hosted
needs:
- prepare
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Bundle play release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: bundlePlayRelease
sign:
name: Sign App Bundle
runs-on: self-hosted
needs:
- build
outputs:
signedReleaseFile: ${{ steps.artifacts.outputs.signedReleaseFile }}
signedReleaseFileRelative: ${{ steps.artifacts.outputs.signedReleaseFileRelative }}
steps:
- name: Sign build artifacts
id: sign_app
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/release
signingKeyBase64: ${{ secrets.KEY_STORE }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_ALIAS_PASSWORD }}
env:
ANDROID_HOME: ${{ needs.build.outputs.androidHome }}
ANDROID_SDK_ROOT: ${{ needs.build.outputs.androidSdkRoot }}
BUILD_TOOLS_VERSION: "30.0.2"
- name: Rename signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/rename_artifacts.py $GITHUB_WORKSPACE
publish:
name: Publish App Bundle
runs-on: self-hosted
needs:
- sign
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Extract changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE
- name: Save version metadata
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE
- name: Publish AAB to Google Play
uses: r0adkll/upload-google-play@v1
if: ${{ endsWith(needs.sign.outputs.signedReleaseFile, '.aab') }}
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
packageName: pl.szczodrzynski.edziennik
releaseFiles: ${{ needs.sign.outputs.signedReleaseFile }}
releaseName: ${{ steps.changelog.outputs.appVersionName }}
track: ${{ secrets.PLAY_RELEASE_TRACK }}
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
status: completed
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: always()
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

View File

@ -1,154 +0,0 @@
name: Release build - official
on:
push:
tags:
- "*"
jobs:
prepare:
name: Prepare build environment
runs-on: self-hosted
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
clean: false
- name: Set executable permissions to gradlew
run: chmod +x ./gradlew
- name: Setup Python
uses: actions/setup-python@v2
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
python-dotenv
pycryptodome
mysql-connector-python
requests
- name: Write signing passwords
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
run: python $GITHUB_WORKSPACE/.github/utils/sign.py $GITHUB_WORKSPACE commit
build:
name: Build APK
runs-on: self-hosted
needs:
- prepare
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}
steps:
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: 'temurin'
java-version: '11'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Clean build artifacts
run: |
rm -rf app/release/*
rm -rf app/build/outputs/apk/*
rm -rf app/build/outputs/bundle/*
- name: Assemble official release with Gradle
uses: gradle/gradle-build-action@v2
with:
arguments: assembleOfficialRelease
sign:
name: Sign APK
runs-on: self-hosted
needs:
- build
outputs:
signedReleaseFile: ${{ steps.artifacts.outputs.signedReleaseFile }}
signedReleaseFileRelative: ${{ steps.artifacts.outputs.signedReleaseFileRelative }}
steps:
- name: Sign build artifacts
id: sign_app
uses: r0adkll/sign-android-release@v1
with:
releaseDirectory: app/release
signingKeyBase64: ${{ secrets.KEY_STORE }}
alias: ${{ secrets.KEY_ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_ALIAS_PASSWORD }}
env:
ANDROID_HOME: ${{ needs.build.outputs.androidHome }}
ANDROID_SDK_ROOT: ${{ needs.build.outputs.androidSdkRoot }}
BUILD_TOOLS_VERSION: "30.0.2"
- name: Rename signed artifacts
id: artifacts
run: python $GITHUB_WORKSPACE/.github/utils/rename_artifacts.py $GITHUB_WORKSPACE
publish:
name: Publish APK
runs-on: self-hosted
needs:
- sign
steps:
- name: Setup Python
uses: actions/setup-python@v2
- name: Extract changelogs
id: changelog
run: python $GITHUB_WORKSPACE/.github/utils/extract_changelogs.py $GITHUB_WORKSPACE
- name: Upload APK to SFTP
uses: easingthemes/ssh-deploy@v2.1.6
env:
REMOTE_HOST: ${{ secrets.SSH_IP }}
REMOTE_USER: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: ${{ needs.sign.outputs.signedReleaseFileRelative }}
TARGET: ${{ secrets.SSH_PATH_RELEASE }}
- name: Save version metadata
env:
DB_HOST: ${{ secrets.DB_HOST }}
DB_USER: ${{ secrets.DB_USER }}
DB_PASS: ${{ secrets.DB_PASS }}
DB_NAME: ${{ secrets.DB_NAME }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
run: python $GITHUB_WORKSPACE/.github/utils/save_version.py $GITHUB_WORKSPACE
- name: Distribute to App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: ${{ secrets.FIREBASE_GROUPS_RELEASE }}
file: ${{ needs.sign.outputs.signedReleaseFile }}
releaseNotesFile: ${{ steps.changelog.outputs.changelogPlainTitledFile }}
- name: Release on GitHub
uses: softprops/action-gh-release@v1
with:
name: ${{ steps.changelog.outputs.changelogTitle }}
body_path: ${{ steps.changelog.outputs.changelogMarkdownFile }}
files: ${{ needs.sign.outputs.signedReleaseFile }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Post Discord webhook
env:
APK_FILE: ${{ needs.sign.outputs.signedReleaseFile }}
APK_SERVER_RELEASE: ${{ secrets.APK_SERVER_RELEASE }}
APK_SERVER_NIGHTLY: ${{ secrets.APK_SERVER_NIGHTLY }}
WEBHOOK_RELEASE: ${{ secrets.WEBHOOK_RELEASE }}
WEBHOOK_TESTING: ${{ secrets.WEBHOOK_TESTING }}
run: python $GITHUB_WORKSPACE/.github/utils/webhook_discord.py $GITHUB_WORKSPACE
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: true
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |
app/release/whatsnew*/
app/release/*.apk
app/release/*.aab
app/release/*.json
app/release/*.txt

13
.github/workflows/push-master.yml vendored Normal file
View File

@ -0,0 +1,13 @@
name: Push (master)
on:
push:
branches: ["master"]
jobs:
build:
name: Build for Google Play (AAB)
uses: szkolny-eu/szkolny-android/.github/workflows/_build.yml@develop
with:
build-aab: true
release-ssh: true
release-google-play: true
secrets: inherit

15
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Release
on:
push:
tags: ["v*.*.*"]
jobs:
build:
name: Build release (APK)
uses: szkolny-eu/szkolny-android/.github/workflows/_build.yml@develop
with:
build-apk: true
release-ssh: true
release-github: true
release-firebase: true
release-discord: true
secrets: inherit

42
.github/workflows/schedule-dispatch.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: Schedule/dispatch
on:
schedule:
# 23:30 UTC, 0:30 or 1:30 CET/CEST
- cron: "30 23 * * *"
workflow_dispatch:
jobs:
check:
name: Check new changes
runs-on: ubuntu-latest
outputs:
hasNewChanges: ${{ steps.nightly.outputs.hasNewChanges }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
clean: false
- name: Setup Python
uses: actions/setup-python@v4
- name: Install packages
uses: BSFishy/pip-action@v1
with:
packages: |
requests
- name: Check new changes
id: nightly
run: python $GITHUB_WORKSPACE/.github/utils/check_nightly.py $GITHUB_WORKSPACE >> $GITHUB_OUTPUT
build:
name: Build nightly release (APK)
needs:
- check
if: ${{ needs.check.outputs.hasNewChanges == 'true' }}
uses: szkolny-eu/szkolny-android/.github/workflows/_build.yml@develop
with:
nightly: true
build-apk: true
release-ssh: true
release-firebase: true
release-discord: true
secrets: inherit

View File

@ -104,7 +104,6 @@ android {
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
lint {
@ -113,8 +112,9 @@ android {
}
tasks.whenTaskAdded { task ->
if (!task.name.endsWith("Release") && !task.name.endsWith("ReleaseWithR8"))
if (!(task.name == "assembleUnofficialRelease" || task.name == "assembleOfficialRelease" || task.name == "signPlayReleaseBundle"))
return
def renameTaskName = "rename${task.name.capitalize()}"
def flavor = ""
@ -124,17 +124,22 @@ tasks.whenTaskAdded { task ->
flavor = task.name.substring("assemble".length(), task.name.indexOf("Release")).uncapitalize()
if (task.name.startsWith("minify"))
flavor = task.name.substring("minify".length(), task.name.indexOf("Release")).uncapitalize()
if (task.name.startsWith("sign"))
flavor = task.name.substring("sign".length(), task.name.indexOf("Release")).uncapitalize()
if (flavor != "") {
tasks.create(renameTaskName, Copy) {
tasks.register(renameTaskName, Copy) {
dependsOn(task.name)
duplicatesStrategy DuplicatesStrategy.FAIL
from file("${projectDir}/${flavor}/release/"),
file("${buildDir}/outputs/mapping/${flavor}Release/"),
file("${buildDir}/outputs/apk/${flavor}/release/"),
file("${buildDir}/outputs/bundle/${flavor}Release/")
include "*.aab", "*.apk", "mapping.txt", "output-metadata.json"
file("${projectDir}/build/outputs/apk/${flavor}/release/"),
file("${projectDir}/build/outputs/mapping/${flavor}Release/"),
file("${projectDir}/build/outputs/bundle/${flavor}Release/")
include "*-release.aab", "*-release.apk", "mapping.txt", "output-metadata.json"
destinationDir file("${projectDir}/release/")
rename ".+?\\.(.+)", "Edziennik_${android.defaultConfig.versionName}_${flavor}." + '$1'
}
task.finalizedBy(renameTaskName)
}
}

View File

@ -1,8 +1,6 @@
<h3>Wersja 4.13.6, 2023-03-24</h3>
<h3>Wersja 4.13.7, 2024-07-08</h3>
<ul>
<li>Naprawiono pobieranie załączników na Androidzie 13 i nowszym.</li>
<li>Dodano opcję odświeżenia planu lekcji na wybrany tydzień.</li>
<li>Usunięto błędy logowania. @BxOxSxS</li>
<li>Dodano opcję uruchomienia aplikacji bez logowania.</li>
</ul>
<br>
<br>

View File

@ -5,6 +5,8 @@
cmake_minimum_required(VERSION 3.4.1)
project(szkolny-signing)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
@ -41,4 +43,4 @@ target_link_libraries( # Specifies the target library.
# Links the target library to the log library
# included in the NDK.
${log-lib} )
${log-lib} )

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/
static toys AES_IV[16] = {
0x6d, 0xa5, 0x32, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0x0e, 0x87, 0x6d, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -9,6 +9,7 @@ import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.ERROR_PROFILE_ARCHIVED
import pl.szczodrzynski.edziennik.data.api.edziennik.demo.Demo
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie
@ -120,6 +121,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
LoginType.PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
LoginType.TEMPLATE -> Template(app, profile, loginStore, taskCallback)
LoginType.USOS -> Usos(app, profile, loginStore, taskCallback)
LoginType.DEMO -> Demo(app, profile, loginStore, taskCallback)
else -> null
}
if (edziennikInterface == null) {

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) Kuba Szczodrzyński 2024-7-8.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.demo
import com.google.gson.JsonObject
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
class Demo(
val app: App,
val profile: Profile?,
val loginStore: LoginStore,
val callback: EdziennikCallback,
) : EdziennikInterface {
private fun completed() {
callback.onCompleted()
}
override fun sync(
featureTypes: Set<FeatureType>?,
onlyEndpoints: Set<Int>?,
arguments: JsonObject?,
) = completed()
override fun getMessage(message: MessageFull) =
completed()
override fun sendMessage(recipients: Set<Teacher>, subject: String, text: String) =
completed()
override fun markAllAnnouncementsAsRead() =
completed()
override fun getAnnouncement(announcement: AnnouncementFull) =
completed()
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) =
completed()
override fun getRecipientList() =
completed()
override fun getEvent(eventFull: EventFull) =
completed()
override fun firstLogin() {
val profile = Profile(
id = loginStore.id,
loginStoreId = loginStore.id,
loginStoreType = LoginType.DEMO,
name = "Jan Szkolny",
subname = "Szkolny.eu",
studentNameLong = "Jan Szkolny",
studentNameShort = "Jan S.",
accountName = null,
)
profile.apply {
empty = false
syncEnabled = false
registration = Profile.REGISTRATION_DISABLED
studentClassName = "1A"
userCode = "nologin:1234"
dateYearEnd.month = 8
}
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(profile), loginStore))
completed()
}
override fun cancel() {}
}

View File

@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MD01uMP7oW===.$param2".sha256()
return "$param1.MTIzNDU2Nzg5MD0WAYwfGc===.$param2".sha256()
}
}

View File

@ -17,4 +17,5 @@ enum class LoginMode(
VULCAN_HEBE(LoginType.VULCAN, id = 402),
PODLASIE_API(LoginType.PODLASIE, id = 600),
USOS_OAUTH(LoginType.USOS, id = 700),
DEMO(LoginType.DEMO, id = 800),
}

View File

@ -14,7 +14,7 @@ enum class LoginType(
VULCAN(id = 4, features = FEATURES_VULCAN),
PODLASIE(id = 6, features = FEATURES_PODLASIE),
USOS(id = 7, features = FEATURES_USOS, schoolType = SchoolType.UNIVERSITY),
DEMO(id = 20, features = setOf()),
DEMO(id = 8, features = setOf()),
TEMPLATE(id = 21, features = setOf()),
// the graveyard

View File

@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.config.AppData
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.enums.FeatureType
import pl.szczodrzynski.edziennik.data.db.enums.LoginType
import pl.szczodrzynski.edziennik.utils.ProfileImageHolder
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.navlib.ImageHolder
@ -71,6 +72,8 @@ fun Profile.getAppData() =
if (App.profileId == this.id) App.data else AppData.get(this.loginStoreType)
fun Profile.shouldArchive(): Boolean {
if (loginStoreType == LoginType.DEMO)
return false
// vulcan hotfix
if (dateYearEnd.month > 6) {
dateYearEnd.month = 6

View File

@ -197,7 +197,7 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
adapter.items.removeAll { it !is LoginInfo.Register }
adapter.items.add(
LoginInfo.Register(
loginType = LoginType.DEMO,
loginType = LoginType.TEMPLATE,
registerName = R.string.eggs,
registerLogo = R.drawable.face_1,
loginModes = listOf(
@ -241,13 +241,13 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
loginType: LoginInfo.Register,
loginMode: LoginInfo.Mode
) {
if (loginType.loginType == LoginType.DEMO) {
nav.navigate(R.id.loginEggsFragment, null, activity.navOptions)
return
}
if (loginType.loginType == LoginType.TEMPLATE) {
nav.navigate(R.id.labFragment, null, activity.navOptions)
when (loginType.registerName) {
R.string.eggs ->
nav.navigate(R.id.loginEggsFragment, null, activity.navOptions)
R.string.menu_lab ->
nav.navigate(R.id.labFragment, null, activity.navOptions)
}
return
}

View File

@ -328,6 +328,21 @@ object LoginInfo {
),
),
),
Register(
loginType = LoginType.DEMO,
registerName = R.string.login_type_demo,
registerLogo = R.mipmap.ic_launcher,
loginModes = listOf(
Mode(
loginMode = LoginMode.DEMO,
name = R.string.login_mode_demo,
icon = R.mipmap.ic_launcher,
guideText = R.string.login_mode_demo,
credentials = listOf(),
errorCodes = mapOf(),
),
),
),
)
}

View File

@ -1433,4 +1433,6 @@
<string name="menu_agenda_config">Agenda settings</string>
<string name="registration_config_note_sharing_title">Share notes</string>
<string name="home_timetable_all_lessons">All lessons:</string>
<string name="login_type_demo">Use without login</string>
<string name="login_mode_demo">Demo version</string>
</resources>

View File

@ -1553,4 +1553,6 @@
<string name="home_timetable_all_lessons">Wszystkie lekcje:</string>
<string name="agenda_config_subject_important">Wyświetl nazwę przedmiotu zamiast rodzaju</string>
<string name="menu_timetable_sync">Odśwież wybrany tydzień</string>
<string name="login_type_demo">Użyj bez logowania</string>
<string name="login_mode_demo">Wersja demonstracyjna</string>
</resources>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.6.10'
release = [
versionName: "4.13.6",
versionCode: 4130699
versionName: "4.13.7",
versionCode: 4130799
]
setup = [