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/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 0000000..a149e47 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,50 @@ +name: Build preview for pull requests + +on: + push: + # REQUIRED: push main(default) branch is necessary for this action to update its fingerprint database + branches: [master] + pull_request: + types: [opened, synchronize] + +jobs: + build: + runs-on: ubuntu-latest + # REQUIRED: limit concurrency when pushing main(default) branch to prevent conflict for this action to update its fingerprint database + concurrency: fingerprint-${{ github.event_name != 'pull_request' && 'master' || github.run_id }} + permissions: + # REQUIRED: Allow comments of PRs + pull-requests: write # Allow comments on PRs + # REQUIRED: Allow updating fingerprint in acton caches + actions: write + # Following permissions are required for private repos + contents: read + packages: write + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: 🏗 Setup EAS + uses: expo/expo-github-action@v8 + with: + eas-version: latest + token: ${{ secrets.EXPO_TOKEN }} + + - name: Install dependencies + run: npm install + + - name: 🚀 Create preview + if: ${{ github.event_name == 'pull_request' }} + uses: expo/expo-github-action/preview@v8 + with: + command: eas update --auto --branch ${{ github.event.pull_request.head.ref }} + comment: true + qr-target: 'expo-go' + working-directory: ${{ github.workspace }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Create preview builds if needed + uses: expo/expo-github-action/preview-build@main + with: + command: eas build --profile development --platform all + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1e037f7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,110 @@ +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/ + + build-ipa: + runs-on: macos-14 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: set up JDK 18 + uses: actions/setup-java@v4 + with: + java-version: 18 + distribution: temurin + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install && npx expo prebuild --platform ios + + - name: Pod Install + run: cd ios && rm Podfile.lock && pod install --repo-update + + - name: build + run: cd ios && xcodebuild -scheme casdoorapp -workspace casdoorapp.xcworkspace -configuration Release clean archive -archivePath "build/casdoorapp.xcarchive" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO + + - name: archive to ipa + run: | + cd ios + mkdir build/Payload + mv build/casdoorapp.xcarchive/Products/Applications/casdoorapp.app build/Payload/casdoorapp.app + cd build + zip -r casdoorapp.ipa Payload/ + + - name: Update artifact + uses: actions/upload-artifact@v4 + with: + name: casdoorapp.ipa + path: ios/build/casdoorapp.ipa + + semantic-release: + needs: [build-ipa, 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 iOS build artifacts + uses: actions/download-artifact@v4 + with: + name: casdoorapp.ipa + path: release/ios/ + + - 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/app.json b/app.json index 0026bc5..16733a1 100644 --- a/app.json +++ b/app.json @@ -15,16 +15,34 @@ "**/*" ], "ios": { - "supportsTablet": true + "supportsTablet": true, + "bundleIdentifier": "com.zzbs.casdoorapp" }, "android": { "adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png", "backgroundColor": "#ffffff" - } + }, + "package": "com.zzbs.casdoorapp" }, "web": { "favicon": "./assets/favicon.png" - } + }, + "extra": { + "eas": { + "projectId": "d0ddea88-9be6-46db-8aa5-ea6d80cef527" + } + }, + "plugins": [ + [ + "expo-camera", + { + "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera", + "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone", + "recordAudioAndroid": true + } + ] + ], + "owner": "zzbs" } } diff --git a/eas.json b/eas.json new file mode 100644 index 0000000..96bf9bf --- /dev/null +++ b/eas.json @@ -0,0 +1,45 @@ +{ + "cli": { + "version": ">= 10.2.1" + }, + "build": { + "base": { + "android": { + "image": "latest", + "buildType": "apk" + }, + "ios": { + "image": "latest", + "simulator": true + } + }, + "development": { + "extends": "base", + "channel": "development", + "developmentClient": true, + "distribution": "internal", + "android": { + "withoutCredentials": true + }, + "ios": { + "buildConfiguration": "Debug" + } + }, + "preview": { + "extends": "base", + "channel": "preview", + "distribution": "internal", + "ios": { + "simulator": true + } + }, + "production": { + "extends": "base", + "channel": "production", + "autoIncrement": true + } + }, + "submit": { + "production": {} + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9d8d64c..8305466 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "eslint-plugin-import": "^2.28.1", "expo": "~51.0.22", "expo-camera": "~15.0.14", + "expo-dev-client": "~4.0.20", "expo-image": "^1.12.13", "expo-status-bar": "~1.12.1", "expo-updates": "~0.25.21", @@ -37,7 +38,6 @@ "@babel/eslint-parser": "^7.18.9", "@babel/preset-react": "^7.18.6", "@types/react": "~18.2.79", - "@types/react-native": "^0.72.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "eslint": "8.22.0", "eslint-import-resolver-babel-module": "^5.3.2", @@ -5965,19 +5965,6 @@ "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.85.tgz", "integrity": "sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw==" }, - "node_modules/@react-native/virtualized-lists": { - "version": "0.72.8", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz", - "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==", - "dev": true, - "dependencies": { - "invariant": "^2.2.4", - "nullthrows": "^1.1.1" - }, - "peerDependencies": { - "react-native": "*" - } - }, "node_modules/@react-navigation/bottom-tabs": { "version": "6.5.9", "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.9.tgz", @@ -6229,16 +6216,6 @@ "csstype": "^3.0.2" } }, - "node_modules/@types/react-native": { - "version": "0.72.3", - "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.72.3.tgz", - "integrity": "sha512-9+g+DBJIY3bG7+ZlYzKPr9kxTQxUuZQgLWZhYK4RlIcrsm3qaJhL2PU2e/K4CjnzznWCo2Islgec94x2z1pG4Q==", - "dev": true, - "dependencies": { - "@react-native/virtualized-lists": "^0.72.4", - "@types/react": "*" - } - }, "node_modules/@types/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", @@ -9248,6 +9225,98 @@ "expo": "*" } }, + "node_modules/expo-dev-client": { + "version": "4.0.20", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-4.0.20.tgz", + "integrity": "sha512-lSr5PoJSqXD2srzWyPY3sb8kcwRaLWNCVemdQryW796tglm6sTnSbRhmUGtUPvrm6Bk+rZAmQNFsqKh1sjHfqg==", + "dependencies": { + "expo-dev-launcher": "4.0.22", + "expo-dev-menu": "5.0.16", + "expo-dev-menu-interface": "1.8.3", + "expo-manifests": "~0.14.0", + "expo-updates-interface": "~0.16.2" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-launcher": { + "version": "4.0.22", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-4.0.22.tgz", + "integrity": "sha512-U8SR4MphP+QatjmD+sQ7AWtKwy7faPpW2PcaPBPnfzBiDc3yk8Kc2sf6/JyN7bUmvA6PFqTnsSJMlZEWi917OQ==", + "dependencies": { + "ajv": "8.11.0", + "expo-dev-menu": "5.0.16", + "expo-manifests": "~0.14.0", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-launcher/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/expo-dev-launcher/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/expo-dev-launcher/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/expo-dev-menu": { + "version": "5.0.16", + "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-5.0.16.tgz", + "integrity": "sha512-zsUiVCvVWT9ve5EsYEGHGu0dJac13NoEQkmzOjhmvcQXb7+OnKgwtBiNAX6rvponfnx9il506rnyZ+0M9CbwYQ==", + "dependencies": { + "expo-dev-menu-interface": "1.8.3", + "semver": "^7.5.4" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-menu-interface": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/expo-dev-menu-interface/-/expo-dev-menu-interface-1.8.3.tgz", + "integrity": "sha512-QM0LRozeFT5Ek0N7XpV93M+HMdEKRLEOXn0aW5M3uoUlnqC1+PLtF3HMy3k3hMKTTE/kJ1y1Z7akH07T0lunCQ==", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-dev-menu/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/expo-eas-client": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/expo-eas-client/-/expo-eas-client-0.12.0.tgz", diff --git a/package.json b/package.json index cad5de0..117d25d 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "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-community/netinfo": "11.3.1", @@ -31,14 +32,63 @@ "react-native-svg": "15.2.0", "react-native-web": "~0.19.6", "react-native-webview": "13.8.6", - "totp-generator": "^0.0.14" + "totp-generator": "^0.0.14", + "expo-dev-client": "~4.0.20" + }, + "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", + "app.json" + ], + "message": "chore(release): ${nextRelease.version} [skip ci]" + } + ], + [ + "@semantic-release/github", + { + "assets": [ + { + "path": "release/ios/*.ipa", + "label": "iOS" + }, + { + "path": "release/android/*.apk", + "label": "Android" + } + ] + } + ] + ] }, "devDependencies": { "@babel/core": "^7.24.0", "@babel/eslint-parser": "^7.18.9", "@babel/preset-react": "^7.18.6", "@types/react": "~18.2.79", - "@types/react-native": "^0.72.2", "@typescript-eslint/eslint-plugin": "^5.62.0", "eslint": "8.22.0", "eslint-import-resolver-babel-module": "^5.3.2", @@ -46,4 +96,4 @@ "eslint-plugin-unused-imports": "^2.0.0" }, "private": true -} +} \ No newline at end of file