diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 000000000..dcbba0597 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,85 @@ +name: "\U0001F41E Bug report" +description: Create a report to help us improve. +title: "[Bug]: " +type: Bug # Retained to categorize the issue as per organization-level type +body: + - type: markdown + attributes: + value: | + - Before creating an issue, please search the existing issues to see if a similar one has already been created. + - You can search issues by specific labels (e.g. `label:nearby`) or just by typing keywords into the search filter. + - type: textarea + attributes: + label: Summary + description: Summarize your issue (what goes wrong, what did you expect to happen) + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce + description: How can we reproduce the issue? + placeholder: | + 1. Have the app open.. + 2. Go to.. + 3. Click on.. + 4. Observe.. + validations: + required: true + - type: textarea + attributes: + label: Expected behaviour + placeholder: A menu should open.. + validations: + required: true + - type: textarea + attributes: + label: Actual behaviour + placeholder: The app closes unexpectedly.. + validations: + required: true + - type: markdown + attributes: + value: | + # Device information + - type: input + attributes: + label: Device name + description: What make and model device did you encounter this on? + placeholder: Samsung J7 + validations: + required: false + - type: input + attributes: + label: Android version + description: What Android version (e.g., Android 6.0 Marshmallow or Android 11) are you running? Is it the stock version from the manufacturer or a custom ROM ? + placeholder: Android 10 + validations: + required: true + - type: input + attributes: + label: Commons app version + description: You can find this information by clicking the right-most menu in the bottom navigation bar in the app and tapping 'About'. If you are building from our codebase instead of downloading the app, please also mention the branch and build variant (e.g. `master` and `prodDebug`). + placeholder: 3.1.1 + validations: + required: true + - type: textarea + attributes: + label: Device logs + description: Add logcat files here (if possible). Need help? See "[Getting app logs from Android Studio](https://commons-app.github.io/docs.html#getting-app-logs-from-android-studio)". + validations: + required: false + - type: textarea + attributes: + label: Screenshots + description: Add screenshots related to the issue (if available). Can be created by pressing the Volume Down and Power Button at the same time on Android 4.0 and higher. + validations: + required: false + - type: dropdown + attributes: + label: Would you like to work on the issue? + description: Please let us know whether you want to fix the issue by yourself. If not, anyone can get the issue assigned to them. + options: + - "Yes" + - Prefer not + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 000000000..5ac210240 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,30 @@ +name: "⭐️ Feature request" +description: Suggest an idea for this project +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + - Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean. + - Every issue should have exactly one feature request described in it. Please do not file feedback list tickets as it is difficult to parse them and address their individual points. + - Feature Requests are better when they’re open-ended instead of demanding a specific solution e.g: “I want an easier way to do X” instead of “add Y”. + - type: textarea + attributes: + label: What is the user problem or growth opportunity you want to see solved? + validations: + required: false + - type: textarea + attributes: + label: How do you know that this problem exists today? Why is this important? + validations: + required: false + - type: textarea + attributes: + label: Who will benefit from it? + validations: + required: false + - type: textarea + attributes: + label: Anything else you would like to add? + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feedback.yml b/.github/ISSUE_TEMPLATE/feedback.yml new file mode 100644 index 000000000..febde65f6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feedback.yml @@ -0,0 +1,46 @@ +name: "\U0001F4AC Feedback" +description: Share your feedback about the app +labels: ["feedback"] +body: + - type: markdown + attributes: + value: | + - Before creating an issue, please search the existing issues to see if a similar one has already been created. + - You can search issues by specific labels (e.g. `label:nearby`) or just by typing keywords into the search filter. + - type: textarea + attributes: + label: Feedback + description: Share your feedback about the app. + validations: + required: true + - type: input + attributes: + label: Wiki username + placeholder: Jimbo Wales + validations: + required: false + - type: markdown + attributes: + value: | + # Device information + - type: input + attributes: + label: Device name + description: What make and model device did you encounter this on? + placeholder: Samsung J7 + validations: + required: false + - type: input + attributes: + label: Android version + description: What Android version (e.g., Android 6.0 Marshmallow or Android 11) are you running? Is it the stock version from the manufacturer or a custom ROM ? + placeholder: Android 10 + validations: + required: false + - type: input + attributes: + label: Commons app version + description: You can find this information by clicking the right-most menu in the bottom navigation bar in the app and tapping 'About'. If you are building from our codebase instead of downloading the app, please also mention the branch and build variant (e.g. `master` and `prodDebug`). + placeholder: 3.1.1 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/need-help.yml b/.github/ISSUE_TEMPLATE/need-help.yml new file mode 100644 index 000000000..64ddabda6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/need-help.yml @@ -0,0 +1,13 @@ +name: "✋🏻 Need help" +description: Describe the situation which you need help with. +labels: ["help needed"] +body: + - type: markdown + attributes: + value: | + - Describe the situation which you need help with with as much information as possible. + - type: textarea + attributes: + label: Description + validations: + required: true diff --git a/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 405c1b3c2..bc8b03c9e 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -1,17 +1,114 @@ name: Android CI -on: - push +on: [push, pull_request, workflow_dispatch] + +concurrency: + group: build-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true jobs: build: - runs-on: ubuntu-18.04 - + name: Run tests and generate APK + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 1.8 - - name: Build with Gradle - run: ./gradlew -Pcoverage lintBetaDebug pmd checkstyle jacocoTestBetaDebugUnitTestReport \ No newline at end of file + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Cache packages + id: cache-packages + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: gradle-packages-${{ runner.os }}-${{ hashFiles('**/*.gradle', '**/*.gradle.kts', 'gradle.properties') }} + restore-keys: gradle-packages-${{ runner.os }} + + - name: Access test login credentials + run: | + echo "TEST_USER_NAME=${{ secrets.TEST_USER_NAME }}" >> local.properties + echo "TEST_USER_PASSWORD=${{ secrets.TEST_USER_PASSWORD }}" >> local.properties + + - name: AVD cache + if: github.event_name != 'pull_request' + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-tablet-api-24 + + - name: Create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' && github.event_name != 'pull_request' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 24 + force-avd-creation: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + script: echo "Generated AVD snapshot for caching." + + - name: Run Instrumentation tests + if: github.event_name != 'pull_request' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 24 + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + profile: Nexus 10 + script: | + adb shell content insert --uri content://settings/system --bind name:s:accelerometer_rotation --bind value:i:0 + adb shell content insert --uri content://settings/system --bind name:s:user_rotation --bind value:i:0 + adb emu geo fix 37.422131 -122.084801 + ./gradlew connectedBetaDebugAndroidTest --stacktrace + + - name: Run Unit tests with unified coverage + if: github.event_name != 'pull_request' + run: ./gradlew -Pcoverage testBetaDebugUnitTestUnifiedCoverage --stacktrace + + - name: Run Unit tests without unified coverage + if: github.event_name == 'pull_request' + run: ./gradlew -Pcoverage testBetaDebugUnitTestCoverage --stacktrace + + - name: Upload Test Report to Codecov + if: github.event_name != 'pull_request' + run: | + curl -Os https://uploader.codecov.io/latest/linux/codecov + chmod +x codecov + ./codecov -f "app/build/reports/jacoco/testBetaDebugUnitTestUnifiedCoverage/testBetaDebugUnitTestUnifiedCoverage.xml" -Z + + - name: Generate betaDebug APK + run: bash ./gradlew assembleBetaDebug --stacktrace + + - name: Upload betaDebug APK + uses: actions/upload-artifact@v4 + with: + name: betaDebugAPK + path: app/build/outputs/apk/beta/debug/app-*.apk + + - name: Generate prodDebug APK + run: bash ./gradlew assembleProdDebug --stacktrace + + - name: Upload prodDebug APK + uses: actions/upload-artifact@v4 + with: + name: prodDebugAPK + path: app/build/outputs/apk/prod/debug/app-*.apk + + - name: Create and PR number artifact + run: | + echo "{\"pr_number\": ${{ github.event.pull_request.number || 'null' }}}" > pr_number.json + + - name: Upload PR number artifact + uses: actions/upload-artifact@v4 + with: + name: pr_number + path: ./pr_number.json diff --git a/.github/workflows/build-beta.yml b/.github/workflows/build-beta.yml new file mode 100644 index 000000000..8e1a26e15 --- /dev/null +++ b/.github/workflows/build-beta.yml @@ -0,0 +1,41 @@ +name: Build beta only + +on: [workflow_dispatch] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: gradle + + - name: Access test login credentials + run: | + echo "TEST_USER_NAME=${{ secrets.TEST_USER_NAME }}" >> local.properties + echo "TEST_USER_PASSWORD=${{ secrets.TEST_USER_PASSWORD }}" >> local.properties + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Set env + run: echo "COMMIT_SHA=$(git log -n 1 --format='%h')" >> $GITHUB_ENV + + - name: Generate betaDebug APK + run: ./gradlew assembleBetaDebug --stacktrace + + - name: Rename betaDebug APK + run: mv app/build/outputs/apk/beta/debug/app-*.apk app/build/outputs/apk/beta/debug/apps-android-commons-betaDebug-$COMMIT_SHA.apk + + - name: Upload betaDebug APK + uses: actions/upload-artifact@v4 + with: + name: apps-android-commons-betaDebugAPK-${{ env.COMMIT_SHA }} + path: app/build/outputs/apk/beta/debug/*.apk + retention-days: 30 diff --git a/.github/workflows/comment_artifacts_on_PR.yml b/.github/workflows/comment_artifacts_on_PR.yml new file mode 100644 index 000000000..ee4ae7c46 --- /dev/null +++ b/.github/workflows/comment_artifacts_on_PR.yml @@ -0,0 +1,96 @@ +name: Comment Artifacts on PR + +on: + workflow_run: + workflows: [ "Android CI" ] + types: [ completed ] + +permissions: + pull-requests: write + contents: read + +concurrency: + group: comment-${{ github.event.workflow_run.id }} + cancel-in-progress: true + +jobs: + comment: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' }} + steps: + - name: Download and process artifacts + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const runId = context.payload.workflow_run.id; + + const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: runId, + }); + + const prNumberArtifact = allArtifacts.data.artifacts.find(artifact => artifact.name === "pr_number"); + if (!prNumberArtifact) { + console.log("pr_number artifact not found."); + return; + } + + const download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: prNumberArtifact.id, + archive_format: 'zip', + }); + + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_number.zip`, Buffer.from(download.data)); + const { execSync } = require('child_process'); + execSync('unzip -q pr_number.zip -d ./pr_number/'); + fs.unlinkSync('pr_number.zip'); + + const prData = JSON.parse(fs.readFileSync('./pr_number/pr_number.json', 'utf8')); + const prNumber = prData.pr_number; + + if (!prNumber || prNumber === 'null') { + console.log("No valid PR number found in pr_number.json. Skipping."); + return; + } + + const artifactsToLink = allArtifacts.data.artifacts.filter(artifact => artifact.name !== "pr_number"); + if (artifactsToLink.length === 0) { + console.log("No artifacts to link found."); + return; + } + + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: Number(prNumber), + }); + + const oldComments = comments.data.filter(comment => + comment.body.startsWith("✅ Generated APK variants!") + ); + for (const comment of oldComments) { + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: comment.id, + }); + console.log(`Deleted old comment ID: ${comment.id}`); + }; + + const commentBody = `✅ Generated APK variants!\n` + + artifactsToLink.map(artifact => { + const artifactUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}`; + return `- 🤖 [Download ${artifact.name}](${artifactUrl})`; + }).join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: Number(prNumber), + body: commentBody + }); diff --git a/.gitignore b/.gitignore index 418e4c380..7fa4767a7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,8 @@ app/src/main/jniLibs #https://docs.opencv.org/3.3.0/ /libraries/opencv/javadoc/ captures/* + +# Test and other output +app/jacoco.exec +app/CommonsContributions +app/.* diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 084bac90e..ea0cb3b07 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -16,6 +16,7 @@