diff --git a/.github/semantic.yml b/.github/semantic.yml new file mode 100644 index 0000000..34b7f4d --- /dev/null +++ b/.github/semantic.yml @@ -0,0 +1,12 @@ +# Always validate the PR title AND all the commits +titleAndCommits: true +# Require at least one commit to be valid +# this is only relevant when using commitsOnly: true or titleAndCommits: true, +# which validate all commits by default +anyCommit: true +# Allow use of Merge commits (eg on github: "Merge branch 'master' into feature/ride-unicorns") +# this is only relevant when using commitsOnly: true (or titleAndCommits: true) +allowMergeCommits: false +# Allow use of Revert commits (eg on github: "Revert "feat: ride unicorns"") +# this is only relevant when using commitsOnly: true (or titleAndCommits: true) +allowRevertCommits: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6e73ae7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,62 @@ +name: Build and Release + +on: + workflow_dispatch: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build-apk: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: set up JDK 18 + uses: actions/setup-java@v4 + with: + java-version: 18 + distribution: temurin + + - name: Install npm dependencies + run: | + npm install && npx expo prebuild --platform android + - name: Build Android Release + run: | + cd android && ./gradlew assembleRelease + mv app/build/outputs/apk/release/app-release.apk app/build/outputs/apk/release/casdoorapp.apk + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: casdoorapp.apk + path: android/app/build/outputs/apk/release/ + + semantic-release: + needs: [build-apk] + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - name: Download Android build artifacts + uses: actions/download-artifact@v4 + with: + name: casdoorapp.apk + path: release/android/ + + - name: Run semantic-release + run: npm run release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 3d3796e..485b7b8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,35 @@ cd casdoor-app npm install && npm run start ``` +## Installation + +You can download the latest version of the Casdoor Authenticator App from the GitHub Releases page. + +- Android: Download and install the APK file directly on your device. + +### Building from Source + +If you prefer to build the app yourself, follow these steps: + +### Common Steps + +```bash +git clone git@github.com:casdoor/casdoor-app.git +cd casdoor-app +npm install +``` + +### android build + + ```bash + npm install && npx expo prebuild --platform android + cd android && ./gradlew assembleRelease + ``` + + The APK file in the `app/build/outputs/apk/release/` directory. + +Note: You'll need to have the necessary development environments set up for React Native, Android. Refer to the React Native documentation for detailed setup instructions. + ## Usage - Open the app on your mobile device. diff --git a/package-lock.json b/package-lock.json index f2698cd..b130c7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "casdoor-app", "version": "1.0.0", "dependencies": { + "@react-native-async-storage/async-storage": "1.23.1", + "@react-native-community/masked-view": "^0.1.11", "@react-native-community/netinfo": "11.3.1", "@react-navigation/bottom-tabs": "^6.5.8", "@react-navigation/native": "^6.1.7", @@ -18,6 +20,7 @@ "expo-dev-client": "^4.0.21", "expo-image": "^1.12.13", "expo-status-bar": "~1.12.1", + "expo-system-ui": "~3.0.7", "expo-updates": "~0.25.21", "hotp-totp": "^1.0.6", "prop-types": "^15.8.1", @@ -27,7 +30,10 @@ "react-native-countdown-circle-timer": "^3.2.1", "react-native-gesture-handler": "~2.16.1", "react-native-paper": "^5.10.3", + "react-native-reanimated": "~3.10.1", "react-native-root-toast": "^3.6.0", + "react-native-safe-area-context": "4.10.5", + "react-native-screens": "^3.31.1", "react-native-svg": "15.2.0", "react-native-web": "~0.19.6", "react-native-webview": "13.8.6", @@ -1457,7 +1463,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1538,7 +1543,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", @@ -1798,7 +1802,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.24.7" }, @@ -5569,6 +5572,16 @@ "node": ">=8" } }, + "node_modules/@react-native-community/masked-view": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@react-native-community/masked-view/-/masked-view-0.1.11.tgz", + "integrity": "sha512-rQfMIGSR/1r/SyN87+VD8xHHzDYeHaJq6elOSCAD+0iLagXkSI2pfA0LmSXP21uw5i3em7GkkRjfJ8wpqWXZNw==", + "deprecated": "Repository was moved to @react-native-masked-view/masked-view", + "peerDependencies": { + "react": ">=16.0", + "react-native": ">=0.57" + } + }, "node_modules/@react-native-community/netinfo": { "version": "11.3.1", "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-11.3.1.tgz", @@ -9546,6 +9559,18 @@ "resolved": "https://registry.npmjs.org/expo-structured-headers/-/expo-structured-headers-3.8.0.tgz", "integrity": "sha512-R+gFGn0x5CWl4OVlk2j1bJTJIz4KO8mPoCHpRHmfqMjmrMvrOM0qQSY3V5NHXwp1yT/L2v8aUmFQsBRIdvi1XA==" }, + "node_modules/expo-system-ui": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-3.0.7.tgz", + "integrity": "sha512-KAs72F5JKhdIfPR9ZNVlRubTPK9uUuevPy5oYEp12xNEzSQcjZKvypH5NpwJuNWkXzrp3n3vZ+3pXsudA7J3KA==", + "dependencies": { + "@react-native/normalize-colors": "0.74.85", + "debug": "^4.3.2" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-updates": { "version": "0.25.21", "resolved": "https://registry.npmjs.org/expo-updates/-/expo-updates-0.25.21.tgz", @@ -14231,7 +14256,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.3.tgz", "integrity": "sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==", - "peer": true, "engines": { "node": ">=10" }, @@ -14371,6 +14395,26 @@ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" }, + "node_modules/react-native-reanimated": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.10.1.tgz", + "integrity": "sha512-sfxg6vYphrDc/g4jf/7iJ7NRi+26z2+BszPmvmk0Vnrz6FL7HYljJqTf531F1x6tFmsf+FEAmuCtTUIXFLVo9w==", + "dependencies": { + "@babel/plugin-transform-arrow-functions": "^7.0.0-0", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.0.0-0", + "@babel/plugin-transform-optional-chaining": "^7.0.0-0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0-0", + "@babel/plugin-transform-template-literals": "^7.0.0-0", + "@babel/preset-typescript": "^7.16.7", + "convert-source-map": "^2.0.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-root-siblings": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/react-native-root-siblings/-/react-native-root-siblings-4.1.1.tgz", @@ -14390,20 +14434,18 @@ } }, "node_modules/react-native-safe-area-context": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.7.2.tgz", - "integrity": "sha512-5fy/hRNJ7bI/U2SliOeKf0D80J4lXPc1NsRiNS7Xaz8YTnqlzWib1ViItkwKPfufe54YKzVBMmM32RpdzvO2gg==", - "peer": true, + "version": "4.10.5", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.10.5.tgz", + "integrity": "sha512-Wyb0Nqw2XJ6oZxW/cK8k5q7/UAhg/wbEG6UVf89rQqecDZTDA5ic//P9J6VvJRVZerzGmxWQpVuM7f+PRYUM4g==", "peerDependencies": { "react": "*", "react-native": "*" } }, "node_modules/react-native-screens": { - "version": "3.25.0", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.25.0.tgz", - "integrity": "sha512-TSC2Ad0hh763I8QT6XxMsPXAagQ+RawDSdFtKRvIz9fCYr96AjRwwaqmYivbqlDywOgcRBkIVynkFtp0ThmlYw==", - "peer": true, + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.33.0.tgz", + "integrity": "sha512-3bKeT/kS1g/6XqraBqjDtyyci35LDeDIHMoko74o+Z5p1oLEi697GWFVwsG272FF0iuOullUbuRNzCcEfRBASQ==", "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" diff --git a/package.json b/package.json index fde2cf4..365c5c2 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,12 @@ "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", - "web": "expo start --web" + "web": "expo start --web", + "release": "npx -p semantic-release-expo -p semantic-release -p @semantic-release/git -p @semantic-release/changelog -p @semantic-release/exec semantic-release" }, "dependencies": { + "@react-native-async-storage/async-storage": "1.23.1", + "@react-native-community/masked-view": "^0.1.11", "@react-native-community/netinfo": "11.3.1", "@react-navigation/bottom-tabs": "^6.5.8", "@react-navigation/native": "^6.1.7", @@ -19,6 +22,7 @@ "expo-dev-client": "^4.0.21", "expo-image": "^1.12.13", "expo-status-bar": "~1.12.1", + "expo-system-ui": "~3.0.7", "expo-updates": "~0.25.21", "hotp-totp": "^1.0.6", "prop-types": "^15.8.1", @@ -28,12 +32,61 @@ "react-native-countdown-circle-timer": "^3.2.1", "react-native-gesture-handler": "~2.16.1", "react-native-paper": "^5.10.3", + "react-native-reanimated": "~3.10.1", "react-native-root-toast": "^3.6.0", + "react-native-safe-area-context": "4.10.5", + "react-native-screens": "^3.31.1", "react-native-svg": "15.2.0", "react-native-web": "~0.19.6", "react-native-webview": "13.8.6", "totp-generator": "^0.0.14" }, + "verifyConditions": [ + "semantic-release-expo", + "@semantic-release/changelog", + "@semantic-release/git" + ], + "release": { + "branches": [ + "master" + ], + "plugins": [ + [ + "semantic-release-expo", + { + "versions": { + "version": "${next.raw}", + "android": "${code}", + "ios": "${next.raw}" + } + } + ], + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + [ + "@semantic-release/git", + { + "assets": [ + "package.json", + "package-lock.json", + "app.json" + ], + "message": "chore(release): ${nextRelease.version} [skip ci]" + } + ], + [ + "@semantic-release/github", + { + "assets": [ + { + "path": "release/android/*.apk", + "label": "Android" + } + ] + } + ] + ] + }, "devDependencies": { "@babel/core": "^7.24.0", "@babel/eslint-parser": "^7.18.9",