Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:oppia/oppia-android into test_co…
Browse files Browse the repository at this point in the history
…verage_workflow
  • Loading branch information
adhiamboperes committed Aug 24, 2024
2 parents b6ac67d + a85cc50 commit 374162f
Show file tree
Hide file tree
Showing 32 changed files with 2,859 additions and 220 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
Expand Down
33 changes: 7 additions & 26 deletions .github/workflows/code_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
Expand Down Expand Up @@ -255,10 +255,13 @@ jobs:
name: coverage-report-${{ env.SHARD_NAME }} # Saving with unique names to avoid conflict
path: coverage_reports

evaluate-code-coverage-reports:
evaluate_code_coverage_reports:
name: Evaluate Code Coverage Reports
runs-on: ubuntu-20.04
needs: code_coverage_run
# The expression if: ${{ !cancelled() }} runs a job or step regardless of its success or failure while responding to cancellations,
# serving as a cancellation-compliant alternative to if: ${{ always() }} in concurrent workflows.
if: ${{ !cancelled() }}
env:
CACHE_DIRECTORY: ~/.bazel_cache
steps:
Expand Down Expand Up @@ -305,32 +308,10 @@ jobs:
name: final-coverage-report
path: coverage_reports/CoverageReport.md

publish_coverage_report:
name: Publish Code Coverage Report
needs: evaluate-code-coverage-reports
permissions:
pull-requests: write

# The expression if: ${{ !cancelled() }} runs a job or step regardless of its success or failure while responding to cancellations,
# serving as a cancellation-compliant alternative to if: ${{ always() }} in concurrent workflows.
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Download Generated Markdown Report
uses: actions/download-artifact@v4
with:
name: final-coverage-report

- name: Upload Coverage Report as PR Comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body-path: 'CoverageReport.md'

# Reference: https://github.community/t/127354/7.
check_coverage_results:
name: Check Code Coverage Results
needs: [ compute_changed_files, code_coverage_run, evaluate-code-coverage-reports ]
needs: [ compute_changed_files, code_coverage_run, evaluate_code_coverage_reports ]
# The expression if: ${{ !cancelled() }} runs a job or step regardless of its success or failure while responding to cancellations,
# serving as a cancellation-compliant alternative to if: ${{ always() }} in concurrent workflows.
if: ${{ !cancelled() }}
Expand All @@ -341,5 +322,5 @@ jobs:
run: exit 1

- name: Check that coverage status is passed
if: ${{ needs.evaluate-code-coverage-reports.result != 'success' }}
if: ${{ needs.compute_changed_files.outputs.can_skip_files != 'true' && needs.evaluate_code_coverage_reports.result != 'success' }}
run: exit 1
81 changes: 81 additions & 0 deletions .github/workflows/comment_coverage_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Contains jobs corresponding to publishing coverage reports generated by code_coverage.yml.

name: Comment Coverage Report

# Controls when the action will run. Triggers the workflow on pull request events
# (assigned, opened, synchronize, reopened)

on:
pull_request_target:
types: [assigned, opened, synchronize, reopened]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
check_code_coverage_completed:
name: Check code coverage completed
runs-on: ubuntu-latest
steps:
- name: Wait for code coverage to complete
id: wait-for-coverage
uses: ArcticLampyrid/[email protected]
with:
workflow: code_coverage.yml
sha: auto
allowed-conclusions: |
success
failure
comment_coverage_report:
name: Comment Code Coverage Report
needs: check_code_coverage_completed
permissions:
pull-requests: write

# The expression if: ${{ !cancelled() }} runs a job or step regardless of its success or failure while responding to cancellations,
# serving as a cancellation-compliant alternative to if: ${{ always() }} in concurrent workflows.
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
steps:
- name: Find CI workflow run for PR
id: find-workflow-run
uses: actions/github-script@v7
continue-on-error: true
with:
script: |
// Find the last successful workflow run for the current PR's head
const { owner, repo } = context.repo;
const runsResponse = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: 'code_coverage.yml',
event: 'pull_request',
head_sha: '${{ github.event.pull_request.head.sha }}',
});
const runs = runsResponse.data.workflow_runs;
runs.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
const run = runs[0];
if(!run) {
core.setFailed('Could not find a succesful workflow run for the PR');
return;
}
core.setOutput('run-id', run.id);
- name: Download Generated Markdown Report
uses: actions/download-artifact@v4
if: ${{ !cancelled() }} # IMPORTANT: Upload reports regardless of success or failure status
with:
name: final-coverage-report
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ steps.find-workflow-run.outputs.run-id }}

- name: Upload Coverage Report as PR Comment
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body-path: 'CoverageReport.md'
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

# This workflow has the following jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/static_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
- develop

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
Expand Down
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ def filesToExclude = [
'**/*AppLanguageLocaleHandlerTest*.kt',
'**/*AppLanguageResourceHandlerTest*.kt',
'**/*AppLanguageWatcherMixinTest*.kt',
'**/*ActivityLanguageLocaleHandlerTest*.kt'
'**/*ActivityLanguageLocaleHandlerTest*.kt',
'**/*OptionsFragmentTest*.kt', // Excludes 2 tests.
]
_excludeSourceFiles(filesToExclude)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class PromotedStoryViewModel(
private val promotedStoryClickListener: PromotedStoryClickListener,
private val position: Int,
private val resourceHandler: AppLanguageResourceHandler,
val showClassroomLabel: Boolean,
translationController: TranslationController
) : RecentlyPlayedItemViewModel() {
/** Sets the story title of the recently played story. */
Expand All @@ -38,6 +39,12 @@ class PromotedStoryViewModel(
promotedStory.nextChapterTitle, promotedStory.nextChapterWrittenTranslationContext
)
}
/** Sets the classroom of the recently played story. */
val classroomTitle by lazy {
translationController.extractString(
promotedStory.classroomTitle, promotedStory.classroomWrittenTranslationContext
)
}

/**
* Starts [ResumeLessonActivity] if a saved exploration is selected or [ExplorationActivity] if an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import org.oppia.android.domain.translation.TranslationController
import org.oppia.android.util.data.AsyncResult
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
import org.oppia.android.util.parser.html.StoryHtmlParserEntityType
import org.oppia.android.util.platformparameter.EnableMultipleClassrooms
import org.oppia.android.util.platformparameter.PlatformParameterValue
import javax.inject.Inject

/** View model for [RecentlyPlayedFragment]. */
Expand All @@ -22,6 +24,7 @@ class RecentlyPlayedViewModel private constructor(
@StoryHtmlParserEntityType private val entityType: String,
private val resourceHandler: AppLanguageResourceHandler,
private val translationController: TranslationController,
private val enableMultipleClassrooms: PlatformParameterValue<Boolean>,
private val promotedStoryClickListener: PromotedStoryClickListener,
private val profileId: ProfileId,
) {
Expand All @@ -33,6 +36,8 @@ class RecentlyPlayedViewModel private constructor(
@StoryHtmlParserEntityType private val entityType: String,
private val resourceHandler: AppLanguageResourceHandler,
private val translationController: TranslationController,
@EnableMultipleClassrooms
private val enableMultipleClassrooms: PlatformParameterValue<Boolean>,
) {

/** Creates an instance of [RecentlyPlayedViewModel]. */
Expand All @@ -46,6 +51,7 @@ class RecentlyPlayedViewModel private constructor(
entityType,
resourceHandler,
translationController,
enableMultipleClassrooms,
promotedStoryClickListener,
profileId,
)
Expand Down Expand Up @@ -166,6 +172,7 @@ class RecentlyPlayedViewModel private constructor(
promotedStoryClickListener,
index,
resourceHandler,
enableMultipleClassrooms.value,
translationController
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import androidx.databinding.ObservableField
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import org.oppia.android.app.fragment.FragmentScope
import org.oppia.android.app.model.AudioLanguage
import org.oppia.android.app.model.OppiaLanguage
import org.oppia.android.app.model.Profile
import org.oppia.android.app.model.ProfileId
Expand All @@ -20,7 +20,8 @@ import org.oppia.android.util.data.DataProviders.Companion.combineWith
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
import javax.inject.Inject

/** [ViewModel] for [OptionsFragment]. */
private const val OPTIONS_ITEM_VIEW_MODEL_APP_AUDIO_LANGUAGE_PROVIDER_ID =
"OPTIONS_ITEM_VIEW_MODEL_APP_AUDIO_LANGUAGE_PROVIDER_ID"
private const val OPTIONS_ITEM_VIEW_MODEL_LIST_PROVIDER_ID =
"OPTIONS_ITEM_VIEW_MODEL_LIST_PROVIDER_ID"

Expand Down Expand Up @@ -67,11 +68,14 @@ class OptionControlsViewModel @Inject constructor(
}

private fun createOptionsItemViewModelProvider(): DataProvider<List<OptionsItemViewModel>> {
val appAudioLangProvider =
translationController.getAppLanguage(profileId).combineWith(
profileManagementController.getAudioLanguage(profileId),
OPTIONS_ITEM_VIEW_MODEL_APP_AUDIO_LANGUAGE_PROVIDER_ID
) { appLanguage, audioLanguage -> appLanguage to audioLanguage }
return profileManagementController.getProfile(profileId).combineWith(
translationController.getAppLanguage(profileId),
OPTIONS_ITEM_VIEW_MODEL_LIST_PROVIDER_ID,
::processViewModelList
)
appAudioLangProvider, OPTIONS_ITEM_VIEW_MODEL_LIST_PROVIDER_ID
) { profile, (appLang, audioLang) -> processViewModelList(profile, appLang, audioLang) }
}

private fun processViewModelListsResult(
Expand All @@ -93,12 +97,13 @@ class OptionControlsViewModel @Inject constructor(

private fun processViewModelList(
profile: Profile,
oppiaLanguage: OppiaLanguage
appLanguage: OppiaLanguage,
audioLanguage: AudioLanguage
): List<OptionsItemViewModel> {
return listOfNotNull(
createReadingTextSizeViewModel(profile),
createAppLanguageViewModel(oppiaLanguage),
createAudioLanguageViewModel(profile)
createAppLanguageViewModel(appLanguage),
createAudioLanguageViewModel(audioLanguage)
)
}

Expand All @@ -117,12 +122,14 @@ class OptionControlsViewModel @Inject constructor(
)
}

private fun createAudioLanguageViewModel(profile: Profile): OptionsAudioLanguageViewModel {
private fun createAudioLanguageViewModel(
audioLanguage: AudioLanguage
): OptionsAudioLanguageViewModel {
return OptionsAudioLanguageViewModel(
routeToAudioLanguageListListener,
loadAudioLanguageListListener,
profile.audioLanguage,
resourceHandler.computeLocalizedDisplayName(profile.audioLanguage)
audioLanguage,
resourceHandler.computeLocalizedDisplayName(audioLanguage)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import org.oppia.android.R
import org.oppia.android.app.fragment.FragmentScope
import org.oppia.android.app.model.AudioLanguage
import org.oppia.android.app.model.CellularDataPreference
import org.oppia.android.app.model.Profile
import org.oppia.android.app.model.ProfileId
import org.oppia.android.app.model.Spotlight
import org.oppia.android.app.model.State
Expand Down Expand Up @@ -147,15 +146,15 @@ class AudioFragmentPresenter @Inject constructor(
) as? SpotlightManager
}

private fun getProfileData(): LiveData<String> {
private fun retrieveAudioLanguageCode(): LiveData<String> {
return Transformations.map(
profileManagementController.getProfile(profileId).toLiveData(),
::processGetProfileResult
profileManagementController.getAudioLanguage(profileId).toLiveData(),
::processAudioLanguageResult
)
}

private fun subscribeToAudioLanguageLiveData() {
getProfileData().observe(
retrieveAudioLanguageCode().observe(
activity,
Observer<String> { result ->
audioViewModel.selectedLanguageCode = result
Expand All @@ -165,11 +164,9 @@ class AudioFragmentPresenter @Inject constructor(
}

/** Gets language code by [AudioLanguage]. */
private fun getAudioLanguage(audioLanguage: AudioLanguage): String {
private fun computeLanguageCode(audioLanguage: AudioLanguage): String {
return when (audioLanguage) {
AudioLanguage.HINDI_AUDIO_LANGUAGE -> "hi"
AudioLanguage.FRENCH_AUDIO_LANGUAGE -> "fr"
AudioLanguage.CHINESE_AUDIO_LANGUAGE -> "zh"
AudioLanguage.BRAZILIAN_PORTUGUESE_LANGUAGE -> "pt"
AudioLanguage.ARABIC_LANGUAGE -> "ar"
AudioLanguage.NIGERIAN_PIDGIN_LANGUAGE -> "pcm"
Expand All @@ -178,16 +175,16 @@ class AudioFragmentPresenter @Inject constructor(
}
}

private fun processGetProfileResult(profileResult: AsyncResult<Profile>): String {
val profile = when (profileResult) {
private fun processAudioLanguageResult(languageResult: AsyncResult<AudioLanguage>): String {
val audioLanguage = when (languageResult) {
is AsyncResult.Failure -> {
oppiaLogger.e("AudioFragment", "Failed to retrieve profile", profileResult.error)
Profile.getDefaultInstance()
oppiaLogger.e("AudioFragment", "Failed to retrieve audio language", languageResult.error)
AudioLanguage.AUDIO_LANGUAGE_UNSPECIFIED
}
is AsyncResult.Pending -> Profile.getDefaultInstance()
is AsyncResult.Success -> profileResult.value
is AsyncResult.Pending -> AudioLanguage.AUDIO_LANGUAGE_UNSPECIFIED
is AsyncResult.Success -> languageResult.value
}
return getAudioLanguage(profile.audioLanguage)
return computeLanguageCode(audioLanguage)
}

/** Sets selected language code in presenter and ViewModel. */
Expand Down
Loading

0 comments on commit 374162f

Please sign in to comment.