Compare commits
No commits in common. 'iceraven-2.13.4' and 'fork' have entirely different histories.
iceraven-2
...
fork
@ -1,154 +0,0 @@
|
||||
projects:
|
||||
app:
|
||||
upstream_dependencies:
|
||||
- browser-domains
|
||||
- browser-engine-gecko
|
||||
- browser-errorpages
|
||||
- browser-icons
|
||||
- browser-menu
|
||||
- browser-menu2
|
||||
- browser-session-storage
|
||||
- browser-state
|
||||
- browser-storage-sync
|
||||
- browser-tabstray
|
||||
- browser-thumbnails
|
||||
- browser-toolbar
|
||||
- compose-awesomebar
|
||||
- compose-cfr
|
||||
- concept-awesomebar
|
||||
- concept-base
|
||||
- concept-engine
|
||||
- concept-fetch
|
||||
- concept-menu
|
||||
- concept-push
|
||||
- concept-storage
|
||||
- concept-sync
|
||||
- concept-tabstray
|
||||
- concept-toolbar
|
||||
- feature-accounts
|
||||
- feature-accounts-push
|
||||
- feature-addons
|
||||
- feature-app-links
|
||||
- feature-autofill
|
||||
- feature-awesomebar
|
||||
- feature-contextmenu
|
||||
- feature-customtabs
|
||||
- feature-downloads
|
||||
- feature-findinpage
|
||||
- feature-fxsuggest
|
||||
- feature-intent
|
||||
- feature-logins
|
||||
- feature-media
|
||||
- feature-privatemode
|
||||
- feature-prompts
|
||||
- feature-push
|
||||
- feature-pwa
|
||||
- feature-qr
|
||||
- feature-readerview
|
||||
- feature-recentlyclosed
|
||||
- feature-search
|
||||
- feature-session
|
||||
- feature-share
|
||||
- feature-sitepermissions
|
||||
- feature-syncedtabs
|
||||
- feature-tab-collections
|
||||
- feature-tabs
|
||||
- feature-toolbar
|
||||
- feature-top-sites
|
||||
- feature-webauthn
|
||||
- feature-webcompat
|
||||
- feature-webcompat-reporter
|
||||
- feature-webnotifications
|
||||
- lib-crash
|
||||
- lib-crash-sentry
|
||||
- lib-dataprotect
|
||||
- lib-publicsuffixlist
|
||||
- lib-push-firebase
|
||||
- lib-state
|
||||
- service-contile
|
||||
- service-digitalassetlinks
|
||||
- service-firefox-accounts
|
||||
- service-glean
|
||||
- service-location
|
||||
- service-nimbus
|
||||
- service-pocket
|
||||
- service-sync-autofill
|
||||
- service-sync-logins
|
||||
- support-base
|
||||
- support-images
|
||||
- support-ktx
|
||||
- support-locale
|
||||
- support-remotesettings
|
||||
- support-rusterrors
|
||||
- support-rusthttp
|
||||
- support-rustlog
|
||||
- support-test
|
||||
- support-test-libstate
|
||||
- support-utils
|
||||
- support-webextensions
|
||||
- ui-autocomplete
|
||||
- ui-colors
|
||||
- ui-icons
|
||||
- ui-tabcounter
|
||||
- ui-widgets
|
||||
variants:
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-debug.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-debug.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-debug.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-debug.apk
|
||||
build_type: debug
|
||||
name: fenixDebug
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-release-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-release-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-release-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-release-unsigned.apk
|
||||
build_type: release
|
||||
name: fenixRelease
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-nightly-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-nightly-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-nightly-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-nightly-unsigned.apk
|
||||
build_type: nightly
|
||||
name: fenixNightly
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-beta-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-beta-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-beta-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-beta-unsigned.apk
|
||||
build_type: beta
|
||||
name: fenixBeta
|
||||
- apks:
|
||||
- abi: arm64-v8a
|
||||
fileName: app-fenix-arm64-v8a-benchmark-unsigned.apk
|
||||
- abi: armeabi-v7a
|
||||
fileName: app-fenix-armeabi-v7a-benchmark-unsigned.apk
|
||||
- abi: x86
|
||||
fileName: app-fenix-x86-benchmark-unsigned.apk
|
||||
- abi: x86_64
|
||||
fileName: app-fenix-x86_64-benchmark-unsigned.apk
|
||||
build_type: benchmark
|
||||
name: fenixBenchmark
|
||||
- apks:
|
||||
- abi: noarch
|
||||
fileName: app-debug-androidTest.apk
|
||||
build_type: androidTest
|
||||
name: androidTest
|
@ -0,0 +1,41 @@
|
||||
# Definitions for jobs that run periodically. For details on the format, see
|
||||
# `taskcluster/taskgraph/cron/schema.py`. For documentation, see
|
||||
# `taskcluster/docs/cron.rst`.
|
||||
---
|
||||
|
||||
jobs:
|
||||
- name: nightly
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nd
|
||||
target-tasks-method: nightly
|
||||
when:
|
||||
- {hour: 5, minute: 0}
|
||||
- {hour: 17, minute: 0}
|
||||
- name: nightly-test
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: Nt
|
||||
target-tasks-method: nightly-test
|
||||
when:
|
||||
- {hour: 5, minute: 0}
|
||||
- name: fennec-production
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: fennec-production
|
||||
target-tasks-method: fennec-production
|
||||
when: [] # Force hook only
|
||||
- name: screenshots
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: screenshots-D
|
||||
target-tasks-method: screenshots
|
||||
when: [{weekday: 'Monday', hour: 10, minute: 0}]
|
||||
- name: legacy-api-ui-tests
|
||||
job:
|
||||
type: decision-task
|
||||
treeherder-symbol: legacy-api-ui
|
||||
target-tasks-method: legacy_api_ui_tests
|
||||
when:
|
||||
- {hour: 11, minute: 0}
|
||||
- {hour: 20, minute: 0}
|
@ -0,0 +1,108 @@
|
||||
---
|
||||
cookie-banners:
|
||||
description: Features for cookie banner handling.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
sections-enabled:
|
||||
type: json
|
||||
description: This property provides a lookup table of whether or not the given section should be enabled.
|
||||
growth-data:
|
||||
description: A feature measuring campaign growth data
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature is active"
|
||||
homescreen:
|
||||
description: The homescreen that the user goes to when they press home or new tab.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
sections-enabled:
|
||||
type: json
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled. If the section is enabled, it should be toggleable in the settings screen, and on by default."
|
||||
messaging:
|
||||
description: "Configuration for the messaging system.\n\nIn practice this is a set of growable lookup tables for the\nmessage controller to piece together.\n"
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
actions:
|
||||
type: json
|
||||
description: A growable map of action URLs.
|
||||
message-under-experiment:
|
||||
type: string
|
||||
description: Id or prefix of the message under experiment.
|
||||
messages:
|
||||
type: json
|
||||
description: A growable collection of messages
|
||||
notification-config:
|
||||
type: json
|
||||
description: Configuration of the notification worker for all notification messages.
|
||||
on-control:
|
||||
type: string
|
||||
description: What should be displayed when a control message is selected.
|
||||
enum:
|
||||
- show-next-message
|
||||
- show-none
|
||||
styles:
|
||||
type: json
|
||||
description: "A map of styles to configure message appearance.\n"
|
||||
triggers:
|
||||
type: json
|
||||
description: "A collection of out the box trigger expressions. Each entry maps to a valid JEXL expression.\n"
|
||||
mr2022:
|
||||
description: Features for MR 2022.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
sections-enabled:
|
||||
type: json
|
||||
description: This property provides a lookup table of whether or not the given section should be enabled.
|
||||
nimbus-validation:
|
||||
description: A feature that does not correspond to an application feature suitable for showing that Nimbus is working. This should never be used in production.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
settings-icon:
|
||||
type: string
|
||||
description: The drawable displayed in the app menu for Settings
|
||||
settings-punctuation:
|
||||
type: string
|
||||
description: The emoji displayed in the Settings screen title.
|
||||
settings-title:
|
||||
type: string
|
||||
description: The title of displayed in the Settings screen and app menu.
|
||||
pre-permission-notification-prompt:
|
||||
description: A feature that shows the pre-permission notification prompt.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "if true, the pre-permission notification prompt is shown to the user."
|
||||
re-engagement-notification:
|
||||
description: A feature that shows the re-enagement notification if the user is inactive.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the re-engagement notification is shown to the inactive user."
|
||||
search-term-groups:
|
||||
description: A feature allowing the grouping of URLs around the search term that it came from.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature shows up on the homescreen and on the new tab screen."
|
||||
unified-search:
|
||||
description: A feature allowing user to easily search for specified results directly in the search bar.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature shows up in the search bar."
|
@ -0,0 +1,5 @@
|
||||
# .git-blame-ignore-revs
|
||||
# For #27667 - Remove import-ordering from the list of disabled ktlint rules (#27680)
|
||||
9654b4dfb122b54b04369fe80a2f9c95811478e8
|
||||
# For #26844: Fix ktlint issues and remove them from baseline. (#26901)
|
||||
ffcef5ff2e3f78b6972dd16551f3f653b7035ccc
|
@ -0,0 +1,31 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This CODEOWNERS file defines individuals or teams that are responsible
|
||||
# for code in this repository. Code owners are automatically requested
|
||||
# for review when someone opens a pull request that modifies code that
|
||||
# they own. Order is important; the last matching pattern takes the most
|
||||
# precedence.
|
||||
# A CODEOWNERS file uses a pattern that follows the same rules used in
|
||||
# gitignore files. The pattern is followed by one or more GitHub usernames
|
||||
# or team names using the standard @username or @org/team-name format.
|
||||
# You can also refer to a user by an email address that has been added
|
||||
# to their GitHub account, for example user@example.com.
|
||||
# https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# WARNING: if there is a single syntax error in this file, CODEOWNERS
|
||||
# WILL NOT WORK AT ALL. Please be careful when editing this file.
|
||||
#
|
||||
# You can use the technique described in this blog post to validate
|
||||
# the paths you specify in .gitignore:
|
||||
# http://www.benjaminoakes.com/git/2018/08/10/Testing-changes-to-GitHub-CODEOWNERS/
|
||||
|
||||
# By default the Android Components team will be the owner for everything in
|
||||
# the repo. Unless a later match takes precedence.
|
||||
* @mozilla-mobile/ACT @mozilla-mobile/fenix
|
||||
/.cron.yml @mozilla-mobile/releng @mozilla-mobile/fenix
|
||||
/.taskcluster.yml @mozilla-mobile/releng @mozilla-mobile/fenix
|
||||
/automation/ @mozilla-mobile/fenix
|
||||
/taskcluster/ @mozilla-mobile/releng @mozilla-mobile/fenix
|
||||
/.github/ @mozilla-mobile/fenix
|
@ -0,0 +1,91 @@
|
||||
name: "\U0001F41E Bug report"
|
||||
description: Create a report to help us improve.
|
||||
title: "[Bug]: "
|
||||
labels: ["\U0001F41E bug", "needs:triage"]
|
||||
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.
|
||||
- Have a look at ["I want to file an issue!"][info] for more information.
|
||||
- Read the [Community Participation Guidelines][guidelines] and the [Bugzilla Etiquette guidelines][bugzilla] before filing an issue.
|
||||
|
||||
[info]: https://github.com/mozilla-mobile/fenix#i-want-to-file-an-issue
|
||||
[guidelines]: https://www.mozilla.org/en-US/about/governance/policies/participation/
|
||||
[bugzilla]: https://bugzilla.mozilla.org/page.cgi?id=etiquette.html
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Steps to reproduce the behaviour.
|
||||
placeholder: |
|
||||
1. Have a tab 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: The name of the device model and manufacturer.
|
||||
placeholder: Google Pixel 2
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
attributes:
|
||||
label: Android version
|
||||
description: You can find the Android version information in the About section of your device's system settings.
|
||||
placeholder: Android 10
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Firefox release type
|
||||
description: You can find this information in Settings -> About Firefox.
|
||||
options:
|
||||
- Firefox Nightly
|
||||
- Firefox Beta
|
||||
- Firefox
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Firefox version
|
||||
description: You can find this information in Settings -> About Firefox.
|
||||
placeholder: 89.0.10
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Device logs
|
||||
description: |
|
||||
Device logs or crash information can greatly aid in debugging. You can find some details here on how to [retrieve device logs or crash IDs][log].
|
||||
|
||||
[log]: https://github.com/mozilla-mobile/fenix/wiki/Logging-Crash-Information
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: |
|
||||
If you have any additional information for us, use the field below.
|
||||
Please note, you can attach screenshots or screen recordings here, by
|
||||
dragging and dropping files in the field below.
|
||||
validations:
|
||||
required: false
|
@ -0,0 +1,19 @@
|
||||
---
|
||||
name: "⌛ Performance issue"
|
||||
about: Create a performance issue if the app is slow or it uses too much memory, disk space, battery, or network data
|
||||
title: ""
|
||||
labels: "performance"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Device information
|
||||
|
||||
* Android device: ?
|
||||
* Fenix version: ?
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
name: "\U0001F4BB Web content issue report"
|
||||
about: Create an issue specifically about something wrong with web content while using Fenix
|
||||
title: "[webcontent]"
|
||||
labels: "\U0001F4BB bug"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Site with issue and any steps to reproduce
|
||||
|
||||
### Expected behavior
|
||||
|
||||
### Actual behavior
|
||||
|
||||
### Does toggling Tracking Protection fix the issue? (Press the shield icon in the toolbar while on the site to see toggle)
|
||||
|
||||
### Can you reproduce in Chrome (or other non-Mozilla browser)?
|
||||
<!--- Note: If you can reproduce the same issue in Firefox for Android AND Chrome, this issue is very unlikely to be fixed by our teams. -->
|
||||
<!-- If you cannot reproduce in Chrome and know how to do so, please consider filing a Bugzilla issue here for faster triage https://bugzilla.mozilla.org/enter_bug.cgi?product=GeckoView&component=General -->
|
||||
|
||||
### Device information
|
||||
|
||||
* Android device: ?
|
||||
* Fenix version: ?
|
@ -0,0 +1,24 @@
|
||||
---
|
||||
name: "\U000026CF Investigative Spike"
|
||||
about: Create an investigation spike
|
||||
title: "[Spike]"
|
||||
|
||||
---
|
||||
|
||||
## Title
|
||||
Brief description of what needs to be investigated, including the User story for which the spike is needed.
|
||||
|
||||
## Description
|
||||
Description of what is being investigated, including:
|
||||
Method of investigation (engineering research, prototype, etc.
|
||||
Boundaries of investigation (time box to x hours, does not include UX, etc.)
|
||||
|
||||
## Deliverables
|
||||
Description of deliverables, including:
|
||||
Documentation of investigation results (within the spike ticket, or linked to it), including:
|
||||
Findings
|
||||
Recommendations
|
||||
List of possible user stories to implement recommendations, including estimates
|
||||
Next Steps
|
||||
Reach out to Product to go over results of investigation.
|
||||
|
@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "\U0001F4C8 Telemetry User Story"
|
||||
about: Create a telemetry user story, assigned to an Epic to track telemetry
|
||||
title: "[Telemetry]"
|
||||
labels: Feature:Telemetry
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Description & Product Manager / Data Scientist User Story
|
||||
|
||||
## What questions will you answer with this data?
|
||||
|
||||
## Acceptance Criteria
|
||||
- [ ] ENG files a [DS JIRA](https://jira.mozilla.com/projects/DO/issues/DO-228?filter=allopenissues) request outlining their methodology.
|
||||
- [ ] DS sign off on instrumentation methodology addressing product questions.
|
||||
- [ ] Event pings can be queried via re:dash
|
||||
- [ ] Event pings can be queried via amplitude
|
||||
- [ ] We are sending telemetry events for the actions listed in the requirements
|
||||
- [ ] We have documented the telemetry
|
||||
- [ ] We have asked a data steward to [review](https://github.com/mozilla/data-review/blob/master/request.md) the telemetry
|
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: "\U0001F494 Intermittent UI Test Issue"
|
||||
about: Create an issue to help log a UI test failure
|
||||
labels: "eng:ui-test, intermittent-test"
|
||||
title: "Intermittent UI test failure - <Classname.testName>"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Firebase Test Run:
|
||||
Provide a Firebase test run report link here showcasing the problem
|
||||
### Stacktrace:
|
||||
### Build:
|
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: "\U0001F6A8 Intermittent Unit Test Issue"
|
||||
about: Create an issue to help log a Unit Test failure
|
||||
labels: "eng:intermittent-test"
|
||||
title: "Intermittent Unit Test failure - <Classname.testName>"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Test Run:
|
||||
Provide a test run report link here showcasing the problem (e.g, Taskcluster), and a link to the source Github event
|
||||
### Stacktrace:
|
||||
### Build:
|
@ -0,0 +1,14 @@
|
||||
|
||||
|
||||
### Pull Request checklist
|
||||
<!-- Before submitting the PR, please address each item -->
|
||||
- [ ] **Tests**: This PR includes thorough tests or an explanation of why it does not
|
||||
- [ ] **Screenshots**: This PR includes screenshots or GIFs of the changes made or an explanation of why it does not
|
||||
- [ ] **Accessibility**: The code in this PR follows [accessibility best practices](https://github.com/mozilla-mobile/shared-docs/blob/master/android/accessibility_guide.md) or does not include any user facing features. In addition, it includes a screenshot of a successful [accessibility scan](https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor&hl=en_US) to ensure no new defects are added to the product.
|
||||
|
||||
### To download an APK when reviewing a PR:
|
||||
The PR runs an Android build check (`run-build`) that builds a `forkRelease` variant of the app. If it succeeds, then we upload the apks (signed with debug keys) via Github actions. We also generate a comment with some instructions and a link to help you find the downloads. You can also follow the instructions below:
|
||||
1. Click Details next to "run-build (pull_request_target)" after it finishes with a green checkmark.
|
||||
2. Click the "Artifacts" drop-down near the top right of the page.
|
||||
3. The apk links should be present in the drop-down menu. You can click on the suitable CPU architecture to download a zipped apk file.
|
||||
4. Unzip the file and install the apk.
|
@ -0,0 +1,115 @@
|
||||
name: Android build PR
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- fork
|
||||
jobs:
|
||||
run-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Install Android SDK with pieces Gradle skips
|
||||
run: ./automation/iceraven/install-sdk.sh
|
||||
- name: Create version name
|
||||
run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
|
||||
- name: Build forkRelease variant of app
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: app:assembleForkRelease -PversionName=${{ env.VERSION_NAME }}
|
||||
|
||||
|
||||
run-testDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run tests
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: testDebug
|
||||
|
||||
|
||||
run-detekt:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run detekt
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: detekt
|
||||
- name: Archive detekt results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: detekt report
|
||||
path: build/reports/detekt.html
|
||||
|
||||
|
||||
run-ktlint:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run ktlint
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: ktlint
|
||||
|
||||
|
||||
run-lintDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run lintDebug
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: lintDebug
|
||||
- name: Archive lint results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lintDebug report
|
||||
path: app/build/reports/lint-results-debug.html
|
@ -0,0 +1,143 @@
|
||||
name: Android build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- fork
|
||||
jobs:
|
||||
run-build:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Install Android SDK with pieces Gradle skips
|
||||
run: ./automation/iceraven/install-sdk.sh
|
||||
- name: Create version name
|
||||
run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
|
||||
- name: Build forkRelease variant of app
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: app:assembleForkRelease -PversionName=${{ env.VERSION_NAME }}
|
||||
- name: Create signed APKs
|
||||
uses: abhijitvalluri/sign-apks@v0.8
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/forkRelease/
|
||||
signingKeyBase64: ${{ secrets.DEBUG_SIGNING_KEY }}
|
||||
alias: ${{ secrets.DEBUG_ALIAS }}
|
||||
keyStorePassword: ${{ secrets.DEBUG_KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.DEBUG_KEY_PASSWORD }}
|
||||
- name: Archive arm64 apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-arm64-v8a-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-arm64-v8a-forkRelease.apk
|
||||
- name: Archive armeabi apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-armeabi-v7a-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-armeabi-v7a-forkRelease.apk
|
||||
- name: Archive x86 apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-x86-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-x86-forkRelease.apk
|
||||
- name: Archive x86_64 apk
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: app-x86_64-forkRelease.apk
|
||||
path: app/build/outputs/apk/forkRelease/app-x86_64-forkRelease.apk
|
||||
|
||||
|
||||
run-testDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run tests
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: testDebug
|
||||
|
||||
|
||||
run-detekt:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run detekt
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: detekt
|
||||
- name: Archive detekt results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: detekt report
|
||||
path: build/reports/detekt.html
|
||||
|
||||
|
||||
run-ktlint:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run ktlint
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: ktlint
|
||||
|
||||
|
||||
run-lintDebug:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.commits.*.message), '[skip ci]')"
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Run lintDebug
|
||||
uses: eskatos/gradle-command-action@v1
|
||||
with:
|
||||
wrapper-cache-enabled: true
|
||||
dependencies-cache-enabled: true
|
||||
configuration-cache-enabled: true
|
||||
arguments: lintDebug
|
||||
- name: Archive lint results
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: lintDebug report
|
||||
path: app/build/reports/lint-results-debug.html
|
@ -0,0 +1,24 @@
|
||||
name: PR comment
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
branches:
|
||||
- fork
|
||||
jobs: # Disabled because we cannot build changes from fork PRs using this repo's secrets due to Github limitations. So, the built apk will be from wrong code, so this is pointless.
|
||||
comment-on-pr:
|
||||
runs-on: ubuntu-latest
|
||||
if: "! contains(toJSON(github.event.pull_request.title), '[skip ci]')"
|
||||
steps:
|
||||
- name: Comment on PR with link to checks page
|
||||
uses: mshick/add-pr-comment@v1
|
||||
with:
|
||||
message: |
|
||||
### Download the built apks
|
||||
You can download the apks built by Github actions **after** the CI checks pass.
|
||||
Please go to the <a href="${{ github.event.pull_request.html_url }}/checks">checks page for this PR</a> to find the zipped apk files under the artifacts drop-down, as seen in the example screenshot below.
|
||||
|
||||
Note that you will have to click on the "Android build PR" tab on the left side to see the artifacts.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/fork-maintainers/iceraven-browser/fork/.github/imgs/download-artifacts-screenshot.png" />
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
allow-repeats: false
|
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
@ -0,0 +1,63 @@
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 180
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 7
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- pin
|
||||
- "feature request 🌟"
|
||||
- "eng:disabled-test"
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: wontfix
|
||||
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
See: https://github.com/mozilla-mobile/fenix/issues/17373
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Comment to post when closing a stale Issue or Pull Request.
|
||||
# closeComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
||||
limitPerRun: 30
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: issues
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
# pulls:
|
||||
# daysUntilStale: 30
|
||||
# markComment: >
|
||||
# This pull request has been automatically marked as stale because it has not had
|
||||
# recent activity. It will be closed if no further activity occurs. Thank you
|
||||
# for your contributions.
|
||||
|
||||
issues:
|
||||
exemptLabels:
|
||||
- pin
|
||||
- "feature request 🌟"
|
@ -1,88 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- iceraven
|
||||
|
||||
jobs:
|
||||
release-automation:
|
||||
name: Build App
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: temurin
|
||||
|
||||
- name: Install Android SDK with pieces Gradle skips
|
||||
run: ./automation/iceraven/install-sdk.sh
|
||||
|
||||
- name: Inspect memory
|
||||
run: free -h
|
||||
|
||||
- name: Create version name
|
||||
run: echo "VERSION_NAME=$(git describe --tags HEAD)" >> $GITHUB_ENV
|
||||
|
||||
- name: Patch on the fly
|
||||
run: |
|
||||
sed -i 's#\.\./version.txt#\./version.txt#g' android-components/plugins/config/src/main/java/ConfigPlugin.kt
|
||||
./automation/iceraven/patch_android_components.sh
|
||||
|
||||
- name: Relpace strings
|
||||
run: |
|
||||
sed -i 's/Firefox/Iceraven/g' app/src/*/res/values*/*strings.xml
|
||||
sed -i '/about_content/s/Mozilla/@forkmaintainers/' app/src/*/res/values*/*strings.xml
|
||||
|
||||
- name: Build forkRelease variant of app
|
||||
uses: gradle/gradle-build-action@v2
|
||||
env:
|
||||
# Try to stop the daemon from magically vanishing by adding random memory-related arguments.
|
||||
# See <https://stackoverflow.com/a/70010526> and <https://stackoverflow.com/a/70756876>
|
||||
# The runner seems to have ~6 gigs of memory, so we make sure to stay under that.
|
||||
# We have Java 11 so we don't have a perm size anymore.
|
||||
GRADLE_OPTS: -Dorg.gradle.jvmargs="-XX:MaxMetaspaceSize=2g -Xms1g -Xmx3g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dev/stderr"
|
||||
with:
|
||||
gradle-home-cache-cleanup: true
|
||||
gradle-executable: /usr/bin/time
|
||||
arguments: -v ./gradlew app:assemblefenixForkRelease -x lintVitalFenixForkRelease -PversionName=${{ env.VERSION_NAME }} --stacktrace
|
||||
|
||||
- name: Create signed APKs
|
||||
uses: abhijitvalluri/sign-apks@v0.8
|
||||
with:
|
||||
releaseDirectory: app/build/outputs/apk/fenix/forkRelease/
|
||||
signingKeyBase64: ${{ secrets.DEBUG_SIGNING_KEY }}
|
||||
alias: ${{ secrets.DEBUG_ALIAS }}
|
||||
keyStorePassword: ${{ secrets.DEBUG_KEY_STORE_PASSWORD }}
|
||||
keyPassword: ${{ secrets.DEBUG_KEY_PASSWORD }}
|
||||
|
||||
- name: Upload arm64 apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-arm64-v8a-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-arm64-v8a-forkRelease.apk
|
||||
|
||||
- name: Upload armeabi apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-armeabi-v7a-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-armeabi-v7a-forkRelease.apk
|
||||
|
||||
- name: Upload x86 apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-x86-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-x86-forkRelease.apk
|
||||
|
||||
- name: Upload x86_64 apk
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: app/build/outputs/apk/fenix/forkRelease/app-fenix-x86_64-forkRelease.apk
|
||||
name: ${{ env.VERSION_NAME }}-browser-x86_64-forkRelease.apk
|
@ -0,0 +1,16 @@
|
||||
name: AssignTriageLabel
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
assign:
|
||||
name: Triage Issues
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add Triage Label
|
||||
uses: boek/AddTriageLabel@v1.2
|
||||
with:
|
||||
repotoken: ${{ secrets.GITHUB_TOKEN }}
|
||||
labeltoadd: "needs:triage"
|
@ -1,3 +0,0 @@
|
||||
[submodule "android-components"]
|
||||
path = android-components
|
||||
url = https://github.com/akliuxingyuan/android-components
|
@ -0,0 +1,122 @@
|
||||
queue_rules:
|
||||
- name: default
|
||||
conditions:
|
||||
- status-success=complete-pr
|
||||
pull_request_rules:
|
||||
- name: Resolve conflict
|
||||
conditions:
|
||||
- conflict
|
||||
actions:
|
||||
comment:
|
||||
message: This pull request has conflicts when rebasing. Could you fix it @{{author}}? 🙏
|
||||
- name: MickeyMoz - Auto Merge
|
||||
conditions:
|
||||
- author=MickeyMoz
|
||||
- status-success=pr-complete
|
||||
- files~=(Gecko.kt|AndroidComponents.kt)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: MickeyMoz 💪
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
- name: L10N - Auto Merge
|
||||
conditions:
|
||||
- author=mozilla-l10n-automation-bot
|
||||
- status-success=pr-complete
|
||||
- files~=(strings.xml|l10n.toml)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: LGTM 😎
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
- name: Release automation (Old)
|
||||
conditions:
|
||||
- base~=releases[_/].*
|
||||
- author=github-actions[bot]
|
||||
# Listing checks manually beause we do not have a "push complete" check yet.
|
||||
- check-success=build-android-test-debug
|
||||
- check-success=build-debug
|
||||
- check-success=build-nightly-simulation
|
||||
- check-success=lint-compare-locales
|
||||
- check-success=lint-detekt
|
||||
- check-success=lint-ktlint
|
||||
- check-success=lint-lint
|
||||
- check-success=signing-android-test-debug
|
||||
- check-success=signing-debug
|
||||
- check-success=signing-nightly-simulation
|
||||
- check-success=test-debug
|
||||
# TODO Temporarily disabled - should be renamed to -build
|
||||
#- check-success=ui-test-x86-debug
|
||||
- files~=(AndroidComponents.kt)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: 🚢
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
delete_head_branch:
|
||||
force: false
|
||||
- name: Release automation (New)
|
||||
conditions:
|
||||
- base~=releases[_/].*
|
||||
- author=github-actions[bot]
|
||||
# Listing checks manually beause we do not have a "push complete" check yet.
|
||||
- check-success=build-android-test-beta
|
||||
- check-success=build-android-test-debug
|
||||
- check-success=build-beta-firebase
|
||||
- check-success=build-debug
|
||||
- check-success=build-nightly-simulation
|
||||
- check-success=lint-compare-locales
|
||||
- check-success=lint-detekt
|
||||
- check-success=lint-ktlint
|
||||
- check-success=lint-lint
|
||||
- check-success=signing-android-test-beta
|
||||
- check-success=signing-beta-firebase
|
||||
- check-success=signing-nightly-simulation
|
||||
- check-success=test-debug
|
||||
- check-success=ui-test-x86-beta
|
||||
- files~=(AndroidComponents.kt)
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
message: 🚢
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
delete_head_branch:
|
||||
force: false
|
||||
- name: Needs landing - Rebase
|
||||
conditions:
|
||||
- check-success=pr-complete
|
||||
- label=pr:needs-landing
|
||||
- "#approved-reviews-by>=1"
|
||||
- -draft
|
||||
- label!=pr:work-in-progress
|
||||
- label!=pr:do-not-land
|
||||
actions:
|
||||
queue:
|
||||
method: rebase
|
||||
name: default
|
||||
rebase_fallback: none
|
||||
- name: Needs landing - Squash
|
||||
conditions:
|
||||
- check-success=pr-complete
|
||||
- label=pr:needs-landing-squashed
|
||||
- "#approved-reviews-by>=1"
|
||||
- -draft
|
||||
- label!=pr:work-in-progress
|
||||
- label!=pr:do-not-land
|
||||
actions:
|
||||
queue:
|
||||
method: squash
|
||||
name: default
|
||||
rebase_fallback: none
|
@ -0,0 +1,293 @@
|
||||
---
|
||||
version: 1
|
||||
reporting: checks-v1
|
||||
policy:
|
||||
# XXX We restrict taskcluster to collaborators so priviledged tests (like UI tests) can run on PRs
|
||||
pullRequests: collaborators
|
||||
tasks:
|
||||
- $let:
|
||||
trustDomain: mobile
|
||||
|
||||
# Github events have this stuff in different places...
|
||||
ownerEmail:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${tasks_for}@noreply.mozilla.org'
|
||||
else:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then:
|
||||
$if: 'event.pusher.email'
|
||||
then: '${event.pusher.email}'
|
||||
else: '${event.pusher.name}@users.noreply.github.com'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.user.login}@users.noreply.github.com'
|
||||
baseRepoUrl:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.repository.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.base.repo.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${repository.url}'
|
||||
repoUrl:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.repository.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.head.repo.html_url}'
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${repository.url}'
|
||||
project:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.repository.name}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.head.repo.name}'
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${repository.project}'
|
||||
head_branch:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: ${event.pull_request.head.ref}
|
||||
else:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: ${event.ref}
|
||||
else:
|
||||
$if: 'tasks_for in ["action", "cron"]'
|
||||
then: '${push.branch}'
|
||||
head_sha:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then: '${event.after}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: '${event.pull_request.head.sha}'
|
||||
else:
|
||||
$if: 'tasks_for in ["action", "cron"]'
|
||||
then: '${push.revision}'
|
||||
ownTaskId:
|
||||
$if: '"github" in tasks_for'
|
||||
then: {$eval: as_slugid("decision_task")}
|
||||
else:
|
||||
$if: 'tasks_for in ["cron", "action"]'
|
||||
then: '${ownTaskId}'
|
||||
pullRequestAction:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then: ${event.action}
|
||||
else: 'UNDEFINED'
|
||||
in:
|
||||
$if: >
|
||||
tasks_for in ["action", "cron"]
|
||||
|| (tasks_for == "github-pull-request" && pullRequestAction in ["opened", "reopened", "synchronize"])
|
||||
|| (tasks_for == "github-push" && head_branch[:10] != "refs/tags/") && (head_branch != "staging.tmp") && (head_branch != "trying.tmp") && (head_branch[:8] != "mergify/")
|
||||
then:
|
||||
$let:
|
||||
level:
|
||||
$if: 'tasks_for in ["github-push", "action", "cron"] && repoUrl == "https://github.com/mozilla-mobile/fenix"'
|
||||
then: '3'
|
||||
else: '1'
|
||||
short_head_branch:
|
||||
$if: 'head_branch[:11] == "refs/heads/"'
|
||||
then: {$eval: 'head_branch[11:]'}
|
||||
in:
|
||||
taskId:
|
||||
$if: 'tasks_for != "action"'
|
||||
then: '${ownTaskId}'
|
||||
taskGroupId:
|
||||
$if: 'tasks_for == "action"'
|
||||
then: '${action.taskGroupId}'
|
||||
else: '${ownTaskId}' # same as taskId; this is how automation identifies a decision task
|
||||
schedulerId: '${trustDomain}-level-${level}'
|
||||
created: {$fromNow: ''}
|
||||
deadline: {$fromNow: '1 day'}
|
||||
expires: {$fromNow: '1 year 1 second'} # 1 second so artifacts expire first, despite rounding errors
|
||||
metadata:
|
||||
$merge:
|
||||
- owner: "${ownerEmail}"
|
||||
source: '${repoUrl}/raw/${head_sha}/.taskcluster.yml'
|
||||
- $if: 'tasks_for in ["github-push", "github-pull-request"]'
|
||||
then:
|
||||
name: "Decision Task"
|
||||
description: 'The task that creates all of the other tasks in the task graph'
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
name: "Action: ${action.title}"
|
||||
description: |
|
||||
${action.description}
|
||||
|
||||
Action triggered by clientID `${clientId}`
|
||||
else:
|
||||
name: "Decision Task for cron job ${cron.job_name}"
|
||||
description: 'Created by a [cron task](https://firefox-ci-tc.services.mozilla.com/tasks/${cron.task_id})'
|
||||
provisionerId: "${trustDomain}-${level}"
|
||||
workerType: "decision-gcp"
|
||||
tags:
|
||||
$if: 'tasks_for in ["github-push", "github-pull-request"]'
|
||||
then:
|
||||
kind: decision-task
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
kind: 'action-callback'
|
||||
else:
|
||||
$if: 'tasks_for == "cron"'
|
||||
then:
|
||||
kind: cron-task
|
||||
routes:
|
||||
$flattenDeep:
|
||||
- checks
|
||||
- $if: 'level == "3" || repoUrl == "https://github.com/mozilla-releng/staging-fenix"'
|
||||
then:
|
||||
- tc-treeherder.v2.${project}.${head_sha}
|
||||
# TODO Bug 1601928: Make this scope fork-friendly once ${project} is better defined. This will enable
|
||||
# staging release promotion on forks.
|
||||
- $if: 'tasks_for == "github-push"'
|
||||
then:
|
||||
- index.${trustDomain}.v2.${project}.branch.${short_head_branch}.latest.taskgraph.decision
|
||||
- index.${trustDomain}.v2.${project}.branch.${short_head_branch}.revision.${head_sha}.taskgraph.decision
|
||||
- index.${trustDomain}.v2.${project}.revision.${head_sha}.taskgraph.decision
|
||||
- $if: 'tasks_for == "cron"'
|
||||
then:
|
||||
# cron context provides ${head_branch} as a short one
|
||||
- index.${trustDomain}.v2.${project}.branch.${head_branch}.latest.taskgraph.decision-${cron.job_name}
|
||||
- index.${trustDomain}.v2.${project}.branch.${head_branch}.revision.${head_sha}.taskgraph.decision-${cron.job_name}
|
||||
- index.${trustDomain}.v2.${project}.branch.${head_branch}.revision.${head_sha}.taskgraph.cron.${ownTaskId}
|
||||
scopes:
|
||||
$if: 'tasks_for == "github-push"'
|
||||
then:
|
||||
# `https://` is 8 characters so, ${repoUrl[8:]} is the repository without the protocol.
|
||||
- 'assume:repo:${repoUrl[8:]}:branch:${short_head_branch}'
|
||||
else:
|
||||
$if: 'tasks_for == "github-pull-request"'
|
||||
then:
|
||||
- 'assume:repo:github.com/${event.pull_request.base.repo.full_name}:pull-request'
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
# when all actions are hooks, we can calculate this directly rather than using a variable
|
||||
- '${action.repo_scope}'
|
||||
else:
|
||||
- 'assume:repo:${repoUrl[8:]}:cron:${cron.job_name}'
|
||||
|
||||
requires: all-completed
|
||||
priority: lowest
|
||||
retries: 5
|
||||
payload:
|
||||
env:
|
||||
# run-task uses these to check out the source; the inputs
|
||||
# to `mach taskgraph decision` are all on the command line.
|
||||
$merge:
|
||||
- MOBILE_BASE_REPOSITORY: '${baseRepoUrl}'
|
||||
MOBILE_HEAD_REPOSITORY: '${repoUrl}'
|
||||
MOBILE_HEAD_REF: '${head_branch}'
|
||||
MOBILE_HEAD_REV: '${head_sha}'
|
||||
MOBILE_REPOSITORY_TYPE: git
|
||||
MOBILE_PIP_REQUIREMENTS: taskcluster/requirements.txt
|
||||
MOZ_AUTOMATION: "1"
|
||||
REPOSITORIES: {$json: {mobile: "Fenix"}}
|
||||
HG_STORE_PATH: /builds/worker/checkouts/hg-store
|
||||
ANDROID_SDK_ROOT: /builds/worker/android-sdk
|
||||
- $if: 'tasks_for in ["github-pull-request"]'
|
||||
then:
|
||||
MOBILE_PULL_REQUEST_NUMBER: '${event.pull_request.number}'
|
||||
- $if: 'tasks_for == "action"'
|
||||
then:
|
||||
ACTION_TASK_GROUP_ID: '${action.taskGroupId}' # taskGroupId of the target task
|
||||
ACTION_TASK_ID: {$json: {$eval: 'taskId'}} # taskId of the target task (JSON-encoded)
|
||||
ACTION_INPUT: {$json: {$eval: 'input'}}
|
||||
ACTION_CALLBACK: '${action.cb_name}'
|
||||
features:
|
||||
taskclusterProxy: true
|
||||
chainOfTrust: true
|
||||
# Note: This task is built server side without the context or tooling that
|
||||
# exist in tree so we must hard code the hash
|
||||
image: mozillareleases/taskgraph:decision-mobile-625975b642c148be4c6f1d8ee5cedf7399f5d0dd33d275ff69d5934e3082d4a9@sha256:bfb26700182486e1c6c52701baea6f386fa39e5e25417423c27845933605ad43
|
||||
|
||||
maxRunTime: 1800
|
||||
|
||||
command:
|
||||
- /usr/local/bin/run-task
|
||||
- '--mobile-checkout=/builds/worker/checkouts/src'
|
||||
- '--task-cwd=/builds/worker/checkouts/src'
|
||||
- '--'
|
||||
- bash
|
||||
- -cx
|
||||
- $let:
|
||||
extraArgs:
|
||||
$if: 'tasks_for == "cron"'
|
||||
then: '${cron.quoted_args}'
|
||||
else: ''
|
||||
in:
|
||||
$if: 'tasks_for == "action"'
|
||||
then: >
|
||||
taskcluster/scripts/decision-install-sdk.sh &&
|
||||
ln -s /builds/worker/artifacts artifacts &&
|
||||
~/.local/bin/taskgraph action-callback
|
||||
else: >
|
||||
taskcluster/scripts/decision-install-sdk.sh &&
|
||||
ln -s /builds/worker/artifacts artifacts &&
|
||||
~/.local/bin/taskgraph decision
|
||||
--pushlog-id='0'
|
||||
--pushdate='0'
|
||||
--project='${project}'
|
||||
--message=""
|
||||
--owner='${ownerEmail}'
|
||||
--level='${level}'
|
||||
--base-repository="$MOBILE_BASE_REPOSITORY"
|
||||
--head-repository="$MOBILE_HEAD_REPOSITORY"
|
||||
--head-ref="$MOBILE_HEAD_REF"
|
||||
--head-rev="$MOBILE_HEAD_REV"
|
||||
--repository-type="$MOBILE_REPOSITORY_TYPE"
|
||||
--tasks-for='${tasks_for}'
|
||||
${extraArgs}
|
||||
|
||||
artifacts:
|
||||
'public':
|
||||
type: 'directory'
|
||||
path: '/builds/worker/artifacts'
|
||||
expires:
|
||||
$fromNow: '1 year'
|
||||
'public/docker-contexts':
|
||||
type: 'directory'
|
||||
path: '/builds/worker/checkouts/src/docker-contexts'
|
||||
# This needs to be at least the deadline of the
|
||||
# decision task + the docker-image task deadlines.
|
||||
# It is set to a week to allow for some time for
|
||||
# debugging, but they are not useful long-term.
|
||||
expires:
|
||||
$fromNow: '7 day'
|
||||
|
||||
extra:
|
||||
$merge:
|
||||
- treeherder:
|
||||
$merge:
|
||||
- machine:
|
||||
platform: gecko-decision
|
||||
- $if: 'tasks_for in ["github-push", "github-pull-request"]'
|
||||
then:
|
||||
symbol: D
|
||||
else:
|
||||
$if: 'tasks_for == "action"'
|
||||
then:
|
||||
groupName: 'action-callback'
|
||||
groupSymbol: AC
|
||||
symbol: "${action.symbol}"
|
||||
else:
|
||||
groupSymbol: cron
|
||||
symbol: "${cron.job_symbol}"
|
||||
- $if: 'tasks_for == "action"'
|
||||
then:
|
||||
parent: '${action.taskGroupId}'
|
||||
action:
|
||||
name: '${action.name}'
|
||||
context:
|
||||
taskGroupId: '${action.taskGroupId}'
|
||||
taskId: {$eval: 'taskId'}
|
||||
input: {$eval: 'input'}
|
||||
clientId: {$eval: 'clientId'}
|
||||
- $if: 'tasks_for == "cron"'
|
||||
then:
|
||||
cron: {$json: {$eval: 'cron'}}
|
||||
- tasks_for: '${tasks_for}'
|
@ -0,0 +1,16 @@
|
||||
language: android
|
||||
dist: trusty
|
||||
script:
|
||||
# Prepare SDK
|
||||
- sudo mkdir -p /usr/local/android-sdk/licenses/
|
||||
- sudo touch /usr/local/android-sdk/licenses/android-sdk-license
|
||||
- echo "8933bad161af4178b1185d1a37fbf41ea5269c55" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
|
||||
- echo "d56f5187479451eabf01fb78af6dfcb131a6481e" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
|
||||
- echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" | sudo tee -a /usr/local/android-sdk/licenses/android-sdk-license
|
||||
# The build needs this but Gradle refuses to fetch it.
|
||||
- sdkmanager "ndk;21.0.6113669"
|
||||
# Run tests
|
||||
- ./gradlew -q testDebug 2>&1
|
||||
# Make sure a release build builds
|
||||
- ./gradlew assembleForkRelease -PversionName="$(git describe --tags HEAD)"
|
||||
|
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
@ -1 +0,0 @@
|
||||
Subproject commit e30cbe7c937c8cb898f87e701335c622f224b65d
|
@ -1,239 +0,0 @@
|
||||
---
|
||||
cookie-banners:
|
||||
description: Features for cookie banner handling.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
sections-enabled:
|
||||
type: json
|
||||
description: This property provides a lookup table of whether or not the given section should be enabled.
|
||||
extensions-process:
|
||||
description: A feature to rollout the extensions process.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the extensions process is enabled."
|
||||
fx-suggest:
|
||||
description: A feature that provides Firefox Suggest search suggestions.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "Whether the feature is enabled. When Firefox Suggest is enabled, Firefox will download and store new search suggestions in the background, and show additional Search settings to control which suggestions appear in the awesomebar. When Firefox Suggest is disabled, Firefox will not download new suggestions, and hide the additional Search settings.\n"
|
||||
glean:
|
||||
description: A feature that provides server-side configurations for Glean metrics (aka Server Knobs).
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enable-event-timestamps:
|
||||
type: boolean
|
||||
description: Enables precise event timestamps for Glean events
|
||||
metrics-enabled:
|
||||
type: json
|
||||
description: "A map of metric base-identifiers to booleans representing the state of the 'enabled' flag for that metric."
|
||||
growth-data:
|
||||
description: A feature measuring campaign growth data
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature is active"
|
||||
homescreen:
|
||||
description: The homescreen that the user goes to when they press home or new tab.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
sections-enabled:
|
||||
type: json
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled. If the section is enabled, it should be toggleable in the settings screen, and on by default."
|
||||
juno-onboarding:
|
||||
description: A feature that shows juno onboarding flow.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
cards:
|
||||
type: json
|
||||
description: Collection of user facing onboarding cards.
|
||||
messaging:
|
||||
description: "The in-app messaging system.\n"
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
actions:
|
||||
type: json
|
||||
description: A growable map of action URLs.
|
||||
message-under-experiment:
|
||||
type: string
|
||||
description: "Deprecated in favor of `MessageData#experiment`. This will be removed in future releases."
|
||||
messages:
|
||||
type: json
|
||||
description: A growable collection of messages
|
||||
notification-config:
|
||||
type: json
|
||||
description: Configuration of the notification worker for all notification messages.
|
||||
on-control:
|
||||
type: string
|
||||
description: What should be displayed when a control message is selected.
|
||||
enum:
|
||||
- show-next-message
|
||||
- show-none
|
||||
styles:
|
||||
type: json
|
||||
description: "A map of styles to configure message appearance.\n"
|
||||
triggers:
|
||||
type: json
|
||||
description: "A collection of out the box trigger expressions. Each entry maps to a valid JEXL expression.\n"
|
||||
mr2022:
|
||||
description: Features for MR 2022.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
sections-enabled:
|
||||
type: json
|
||||
description: This property provides a lookup table of whether or not the given section should be enabled.
|
||||
nimbus-system:
|
||||
description: "Configuration of the Nimbus System in Android.\n"
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
refresh-interval-foreground:
|
||||
type: int
|
||||
description: "The minimum interval in minutes between fetching experiment \nrecipes in the foreground.\n"
|
||||
nimbus-validation:
|
||||
description: A feature that does not correspond to an application feature suitable for showing that Nimbus is working. This should never be used in production.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
settings-icon:
|
||||
type: string
|
||||
description: The drawable displayed in the app menu for Settings
|
||||
settings-punctuation:
|
||||
type: string
|
||||
description: The emoji displayed in the Settings screen title.
|
||||
settings-title:
|
||||
type: string
|
||||
description: The title of displayed in the Settings screen and app menu.
|
||||
onboarding:
|
||||
description: "A feature that configures the new user onboarding page. Note that onboarding is a **first run** feature, and should only be modified by first run experiments."
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
order:
|
||||
type: json
|
||||
description: Determines the order of the onboarding page panels
|
||||
pdfjs:
|
||||
description: PDF.js features
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
download-button:
|
||||
type: boolean
|
||||
description: Download button
|
||||
open-in-app-button:
|
||||
type: boolean
|
||||
description: Open in app button
|
||||
pre-permission-notification-prompt:
|
||||
description: A feature that shows the pre-permission notification prompt.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "if true, the pre-permission notification prompt is shown to the user."
|
||||
print:
|
||||
description: A feature for printing from the share or browser menu.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
browser-print-enabled:
|
||||
type: boolean
|
||||
description: "If true, a print button from the browser menu is available."
|
||||
share-print-enabled:
|
||||
type: boolean
|
||||
description: "If true, a print button from the share menu is available."
|
||||
private-browsing:
|
||||
description: Private Browsing Mode
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
felt-privacy-enabled:
|
||||
type: boolean
|
||||
description: "if true, enable felt privacy related UI"
|
||||
re-engagement-notification:
|
||||
description: A feature that shows the re-engagement notification if the user is inactive.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the re-engagement notification is shown to the inactive user."
|
||||
type:
|
||||
type: int
|
||||
description: The type of re-engagement notification that is shown to the inactive user.
|
||||
search-extra-params:
|
||||
description: A feature that provides additional args for search.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
channel-id:
|
||||
type: json
|
||||
description: The channel Id param name with arg.
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature is active."
|
||||
feature-enabler:
|
||||
type: json
|
||||
description: "The feature enabler param name with arg, NOTE this map could be empty."
|
||||
search-engine:
|
||||
type: string
|
||||
description: The search engine name.
|
||||
search-term-groups:
|
||||
description: A feature allowing the grouping of URLs around the search term that it came from.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature shows up on the homescreen and on the new tab screen."
|
||||
shopping-experience:
|
||||
description: A feature that shows product review quality information.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "if true, the shopping experience feature is shown to the user."
|
||||
product-recommendations:
|
||||
type: boolean
|
||||
description: "if true, recommended products feature is enabled to be shown to the user based on their preference."
|
||||
splash-screen:
|
||||
description: "A feature that extends splash screen duration, allowing additional data fetching time for the app's initial run."
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature is active."
|
||||
maximum_duration_ms:
|
||||
type: int
|
||||
description: The maximum amount of time in milliseconds the splashscreen will be visible while waiting for initialization calls to complete.
|
||||
toolbar:
|
||||
description: The searchbar/awesomebar that user uses to search.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
toolbar-position-top:
|
||||
type: boolean
|
||||
description: "If true, toolbar appears at top of the screen."
|
||||
unified-search:
|
||||
description: A feature allowing user to easily search for specified results directly in the search bar.
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "If true, the feature shows up in the search bar."
|
File diff suppressed because it is too large
Load Diff
@ -1,483 +0,0 @@
|
||||
---
|
||||
about:
|
||||
description: Nimbus Feature Manifest for Fenix (Firefox Android)
|
||||
kotlin:
|
||||
package: org.mozilla.fenix
|
||||
class: .nimbus.FxNimbus
|
||||
channels:
|
||||
- release
|
||||
- beta
|
||||
- nightly
|
||||
- developer
|
||||
- forkDebug
|
||||
- forkRelease
|
||||
includes:
|
||||
- onboarding.fml.yaml
|
||||
- pbm.fml.yaml
|
||||
import:
|
||||
- path: ../android-components/components/service/nimbus/messaging.fml.yaml
|
||||
channel: release
|
||||
features:
|
||||
messaging:
|
||||
- value:
|
||||
triggers:
|
||||
# Using attributes built into the Nimbus SDK
|
||||
USER_RECENTLY_INSTALLED: days_since_install < 7
|
||||
USER_RECENTLY_UPDATED: days_since_update < 7 && days_since_install != days_since_update
|
||||
USER_TIER_ONE_COUNTRY: ('US' in locale || 'GB' in locale || 'CA' in locale || 'DE' in locale || 'FR' in locale)
|
||||
USER_EN_SPEAKER: "'en' in locale"
|
||||
USER_ES_SPEAKER: "'es' in locale"
|
||||
USER_DE_SPEAKER: "'de' in locale"
|
||||
USER_FR_SPEAKER: "'fr' in locale"
|
||||
DEVICE_ANDROID: os == 'Android'
|
||||
DEVICE_IOS: os == 'iOS'
|
||||
ALWAYS: "true"
|
||||
NEVER: "false"
|
||||
DAY_1_AFTER_INSTALL: days_since_install == 1
|
||||
DAY_2_AFTER_INSTALL: days_since_install == 2
|
||||
DAY_3_AFTER_INSTALL: days_since_install == 3
|
||||
DAY_4_AFTER_INSTALL: days_since_install == 4
|
||||
DAY_5_AFTER_INSTALL: days_since_install == 5
|
||||
MORE_THAN_24H_SINCE_INSTALLED_OR_UPDATED: days_since_update >= 1
|
||||
|
||||
# Using custom attributes for the browser
|
||||
I_AM_DEFAULT_BROWSER: "is_default_browser"
|
||||
I_AM_NOT_DEFAULT_BROWSER: "is_default_browser == false"
|
||||
USER_ESTABLISHED_INSTALL: "number_of_app_launches >=4"
|
||||
|
||||
FUNNEL_PAID: "adjust_campaign != ''"
|
||||
FUNNEL_ORGANIC: "adjust_campaign == ''"
|
||||
|
||||
# Using Glean events, specific to the browser
|
||||
INACTIVE_1_DAY: "'app_launched'|eventLastSeen('Hours') >= 24"
|
||||
INACTIVE_2_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 2"
|
||||
INACTIVE_3_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 3"
|
||||
INACTIVE_4_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 4"
|
||||
INACTIVE_5_DAYS: "'app_launched'|eventLastSeen('Days', 0) >= 5"
|
||||
|
||||
# Has the user signed in the last 4 years
|
||||
FXA_SIGNED_IN: "'sync_auth.sign_in'|eventLastSeen('Years', 0) <= 4"
|
||||
FXA_NOT_SIGNED_IN: "'sync_auth.sign_in'|eventLastSeen('Years', 0) > 4"
|
||||
|
||||
# https://mozilla-hub.atlassian.net/wiki/spaces/FJT/pages/11469471/Core+Active
|
||||
USER_INFREQUENT: "'app_launched'|eventCountNonZero('Days', 28) >= 1 && 'app_launched'|eventCountNonZero('Days', 28) < 7"
|
||||
USER_CASUAL: "'app_launched'|eventCountNonZero('Days', 28) >= 7 && 'app_launched'|eventCountNonZero('Days', 28) < 14"
|
||||
USER_REGULAR: "'app_launched'|eventCountNonZero('Days', 28) >= 14 && 'app_launched'|eventCountNonZero('Days', 28) < 21"
|
||||
USER_CORE_ACTIVE: "'app_launched'|eventCountNonZero('Days', 28) >= 21"
|
||||
|
||||
LAUNCHED_ONCE_THIS_WEEK: "'app_launched'|eventSum('Days', 7) == 1"
|
||||
|
||||
actions:
|
||||
ENABLE_PRIVATE_BROWSING: ://enable_private_browsing
|
||||
INSTALL_SEARCH_WIDGET: ://install_search_widget
|
||||
MAKE_DEFAULT_BROWSER: ://make_default_browser
|
||||
VIEW_BOOKMARKS: ://urls_bookmarks
|
||||
VIEW_COLLECTIONS: ://home_collections
|
||||
VIEW_HISTORY: ://urls_history
|
||||
VIEW_HOMESCREEN: ://home
|
||||
OPEN_SETTINGS_ACCESSIBILITY: ://settings_accessibility
|
||||
OPEN_SETTINGS_ADDON_MANAGER: ://settings_addon_manager
|
||||
OPEN_SETTINGS_DELETE_BROWSING_DATA: ://settings_delete_browsing_data
|
||||
OPEN_SETTINGS_LOGINS: ://settings_logins
|
||||
OPEN_SETTINGS_NOTIFICATIONS: ://settings_notifications
|
||||
OPEN_SETTINGS_PRIVACY: ://settings_privacy
|
||||
OPEN_SETTINGS_SEARCH_ENGINE: ://settings_search_engine
|
||||
OPEN_SETTINGS_TRACKING_PROTECTION: ://settings_tracking_protection
|
||||
OPEN_SETTINGS_WALLPAPERS: ://settings_wallpapers
|
||||
OPEN_SETTINGS: ://settings
|
||||
TURN_ON_SYNC: ://turn_on_sync
|
||||
styles:
|
||||
DEFAULT:
|
||||
priority: 50
|
||||
max-display-count: 5
|
||||
SURVEY:
|
||||
priority: 55
|
||||
max-display-count: 1
|
||||
PERSISTENT:
|
||||
priority: 50
|
||||
max-display-count: 20
|
||||
WARNING:
|
||||
priority: 60
|
||||
max-display-count: 10
|
||||
URGENT:
|
||||
priority: 100
|
||||
max-display-count: 10
|
||||
NOTIFICATION:
|
||||
priority: 50
|
||||
max-display-count: 1
|
||||
messages:
|
||||
default-browser:
|
||||
text: default_browser_experiment_card_text
|
||||
surface: homescreen
|
||||
action: "MAKE_DEFAULT_BROWSER"
|
||||
trigger: [ "I_AM_NOT_DEFAULT_BROWSER","USER_ESTABLISHED_INSTALL" ]
|
||||
style: PERSISTENT
|
||||
button-label: preferences_set_as_default_browser
|
||||
default-browser-notification:
|
||||
title: nimbus_notification_default_browser_title
|
||||
text: nimbus_notification_default_browser_text
|
||||
surface: notification
|
||||
style: NOTIFICATION
|
||||
trigger:
|
||||
- I_AM_NOT_DEFAULT_BROWSER
|
||||
- DAY_3_AFTER_INSTALL
|
||||
action: MAKE_DEFAULT_BROWSER
|
||||
|
||||
- channel: developer
|
||||
value:
|
||||
styles:
|
||||
DEFAULT:
|
||||
priority: 50
|
||||
max-display-count: 100
|
||||
EXPIRES_QUICKLY:
|
||||
priority: 100
|
||||
max-display-count: 1
|
||||
notification-config:
|
||||
refresh-interval: 120 # minutes (2 hours)
|
||||
- path: ../android-components/components/browser/engine-gecko/geckoview.fml.yaml
|
||||
channel: release
|
||||
features:
|
||||
pdfjs:
|
||||
- channel: developer
|
||||
value: {
|
||||
download-button: true,
|
||||
open-in-app-button: true
|
||||
}
|
||||
|
||||
features:
|
||||
toolbar:
|
||||
description: The searchbar/awesomebar that user uses to search.
|
||||
variables:
|
||||
toolbar-position-top:
|
||||
description: If true, toolbar appears at top of the screen.
|
||||
type: Boolean
|
||||
default: false
|
||||
homescreen:
|
||||
description: The homescreen that the user goes to when they press home or new tab.
|
||||
variables:
|
||||
sections-enabled:
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled.
|
||||
If the section is enabled, it should be toggleable in the settings screen, and on by default."
|
||||
type: Map<HomeScreenSection, Boolean>
|
||||
default:
|
||||
{
|
||||
"top-sites": true,
|
||||
"jump-back-in": true,
|
||||
"recently-saved": true,
|
||||
"recent-explorations": true,
|
||||
"pocket": true,
|
||||
"pocket-sponsored-stories": true,
|
||||
}
|
||||
defaults:
|
||||
- channel: nightly
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"top-sites": true,
|
||||
"jump-back-in": true,
|
||||
"recently-saved": true,
|
||||
"recent-explorations": true,
|
||||
"pocket": true,
|
||||
}
|
||||
}
|
||||
nimbus-validation:
|
||||
description: "A feature that does not correspond to an application feature suitable for showing
|
||||
that Nimbus is working. This should never be used in production."
|
||||
variables:
|
||||
settings-title:
|
||||
description: The title of displayed in the Settings screen and app menu.
|
||||
type: Text
|
||||
default: browser_menu_settings
|
||||
settings-punctuation:
|
||||
description: The emoji displayed in the Settings screen title.
|
||||
type: String
|
||||
default: ""
|
||||
settings-icon:
|
||||
description: The drawable displayed in the app menu for Settings
|
||||
type: String
|
||||
default: mozac_ic_settings
|
||||
search-term-groups:
|
||||
description: A feature allowing the grouping of URLs around the search term that it came from.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature shows up on the homescreen and on the new tab screen.
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: nightly
|
||||
value:
|
||||
enabled: true
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: true
|
||||
mr2022:
|
||||
description: Features for MR 2022.
|
||||
variables:
|
||||
sections-enabled:
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled."
|
||||
type: Map<MR2022Section, Boolean>
|
||||
default:
|
||||
{
|
||||
"home-onboarding-dialog-existing-users": true,
|
||||
"sync-cfr": true,
|
||||
"wallpapers-selection-tool": true,
|
||||
"jump-back-in-cfr": true,
|
||||
"tcp-cfr": true,
|
||||
"tcp-feature": true,
|
||||
}
|
||||
defaults:
|
||||
- channel: developer
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"home-onboarding-dialog-existing-users": true,
|
||||
"sync-cfr": true,
|
||||
"wallpapers-selection-tool": true,
|
||||
"jump-back-in-cfr": true,
|
||||
}
|
||||
}
|
||||
|
||||
cookie-banners:
|
||||
description: Features for cookie banner handling.
|
||||
variables:
|
||||
sections-enabled:
|
||||
description: "This property provides a lookup table of whether or not the given section should be enabled."
|
||||
type: Map<CookieBannersSection, Int>
|
||||
default:
|
||||
{
|
||||
"feature-ui": 0,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4,
|
||||
"feature-setting-value-pbm": 0
|
||||
}
|
||||
defaults:
|
||||
- channel: developer
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"feature-ui": 1,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4,
|
||||
"feature-setting-value-pbm": 0
|
||||
}
|
||||
}
|
||||
- channel: nightly
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"feature-ui": 1,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4,
|
||||
"feature-setting-value-pbm": 0
|
||||
}
|
||||
}
|
||||
unified-search:
|
||||
description: A feature allowing user to easily search for specified results directly in the search bar.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature shows up in the search bar.
|
||||
type: Boolean
|
||||
default: true
|
||||
|
||||
extensions-process:
|
||||
description: A feature to rollout the extensions process.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the extensions process is enabled.
|
||||
type: Boolean
|
||||
default: true
|
||||
|
||||
growth-data:
|
||||
description: A feature measuring campaign growth data
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature is active
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: release
|
||||
value:
|
||||
enabled: true
|
||||
|
||||
re-engagement-notification:
|
||||
description: A feature that shows the re-engagement notification if the user is inactive.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the re-engagement notification is shown to the inactive user.
|
||||
type: Boolean
|
||||
default: false
|
||||
type:
|
||||
description: The type of re-engagement notification that is shown to the inactive user.
|
||||
type: Int
|
||||
default: 0
|
||||
|
||||
pre-permission-notification-prompt:
|
||||
description: A feature that shows the pre-permission notification prompt.
|
||||
variables:
|
||||
enabled:
|
||||
description: if true, the pre-permission notification prompt is shown to the user.
|
||||
type: Boolean
|
||||
default: false
|
||||
|
||||
onboarding:
|
||||
description: "A feature that configures the new user onboarding page.
|
||||
Note that onboarding is a **first run** feature, and should only be modified by first run experiments."
|
||||
variables:
|
||||
order:
|
||||
description: Determines the order of the onboarding page panels
|
||||
type: List<OnboardingPanel>
|
||||
default: ["themes", "toolbar-placement", "sync", "tcp", "privacy-notice"]
|
||||
|
||||
glean:
|
||||
description: "A feature that provides server-side configurations for Glean metrics (aka Server Knobs)."
|
||||
variables:
|
||||
metrics-enabled:
|
||||
description: "A map of metric base-identifiers to booleans representing the state of the 'enabled' flag for that metric."
|
||||
type: Map<String, Boolean>
|
||||
default: {}
|
||||
enable-event-timestamps:
|
||||
description: "Enables precise event timestamps for Glean events"
|
||||
type: Boolean
|
||||
default: false
|
||||
|
||||
splash-screen:
|
||||
description: "A feature that extends splash screen duration, allowing additional data fetching time for the app's initial run."
|
||||
variables:
|
||||
enabled:
|
||||
description: "If true, the feature is active."
|
||||
type: Boolean
|
||||
default: false
|
||||
maximum_duration_ms:
|
||||
description: The maximum amount of time in milliseconds the splashscreen will be visible while waiting for initialization calls to complete.
|
||||
type: Int
|
||||
default: 0
|
||||
|
||||
shopping-experience:
|
||||
description: A feature that shows product review quality information.
|
||||
variables:
|
||||
enabled:
|
||||
description: if true, the shopping experience feature is shown to the user.
|
||||
type: Boolean
|
||||
default: false
|
||||
product-recommendations:
|
||||
description: if true, recommended products feature is enabled to be shown to the user based on their preference.
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: true
|
||||
|
||||
print:
|
||||
description: A feature for printing from the share or browser menu.
|
||||
variables:
|
||||
share-print-enabled:
|
||||
description: If true, a print button from the share menu is available.
|
||||
type: Boolean
|
||||
default: true
|
||||
browser-print-enabled:
|
||||
description: If true, a print button from the browser menu is available.
|
||||
type: Boolean
|
||||
default: true
|
||||
|
||||
search-extra-params:
|
||||
description: A feature that provides additional args for search.
|
||||
variables:
|
||||
enabled:
|
||||
description: If true, the feature is active.
|
||||
type: Boolean
|
||||
default: false
|
||||
search-engine:
|
||||
description: The search engine name.
|
||||
type: String
|
||||
default: ""
|
||||
feature-enabler:
|
||||
description: The feature enabler param name with arg, NOTE this map could be empty.
|
||||
type: Map<String, String>
|
||||
default: {}
|
||||
channel-id:
|
||||
description: The channel Id param name with arg.
|
||||
type: Map<String, String>
|
||||
default: {}
|
||||
|
||||
fx-suggest:
|
||||
description: A feature that provides Firefox Suggest search suggestions.
|
||||
variables:
|
||||
enabled:
|
||||
description: >
|
||||
Whether the feature is enabled. When Firefox Suggest is enabled,
|
||||
Firefox will download and store new search suggestions in the
|
||||
background, and show additional Search settings to control which
|
||||
suggestions appear in the awesomebar. When Firefox Suggest is
|
||||
disabled, Firefox will not download new suggestions, and hide the
|
||||
additional Search settings.
|
||||
type: Boolean
|
||||
default: false
|
||||
defaults:
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: true
|
||||
- channel: nightly
|
||||
value:
|
||||
enabled: true
|
||||
types:
|
||||
objects: {}
|
||||
|
||||
enums:
|
||||
HomeScreenSection:
|
||||
description: The identifiers for the sections of the homescreen.
|
||||
variants:
|
||||
top-sites:
|
||||
description: The frecency and pinned sites.
|
||||
recently-saved:
|
||||
description: The sites the user has bookmarked recently.
|
||||
jump-back-in:
|
||||
description: The tabs the user was looking immediately before being interrupted.
|
||||
recent-explorations:
|
||||
description: The tab groups
|
||||
pocket:
|
||||
description: The pocket section. This should only be available in the US.
|
||||
pocket-sponsored-stories:
|
||||
description: Subsection of the Pocket homescreen section which shows sponsored stories.
|
||||
|
||||
MR2022Section:
|
||||
description: The identifiers for the sections of the MR 2022.
|
||||
variants:
|
||||
home-onboarding-dialog-existing-users:
|
||||
description: Home onboarding dialog for upgraded users.
|
||||
sync-cfr:
|
||||
description: CFR for the first time you see a synced tab on the home screen.
|
||||
wallpapers-selection-tool:
|
||||
description: Wallpapers selection dialog tool for the home screen.
|
||||
jump-back-in-cfr:
|
||||
description: Jump back-in onboarding message.
|
||||
tcp-cfr:
|
||||
description: CFR for the first time you use the browse with Total Cookie Protection on the browser screen.
|
||||
tcp-feature:
|
||||
description: Controls the Total Cookie Protection feature.
|
||||
CookieBannersSection:
|
||||
description: The identifiers for the sections of the MR 2022.
|
||||
variants:
|
||||
feature-ui:
|
||||
description: An integer either 0 or 1 indicating if the UI for cookie banner handling should be visible,
|
||||
0 to hide the UI and 1 to show the UI. The actual UI is composed by cookie banner section
|
||||
in the settings page, the toolbar section and the re-engagement dialog.
|
||||
feature-setting-value:
|
||||
description: An integer either 0 or 1 indicating if cookie banner setting should be enabled or disabled,
|
||||
0 for setting the value to disabled, 1 for enabling the setting with the value reject_all.
|
||||
dialog-re-engage-time:
|
||||
description: An integer indicating the number of hours that needs to happen before
|
||||
the re-engagement dialog shows again since the last seen, for example if set to 4
|
||||
that means if the users has seen the dialog, it will see it 4 hours later.
|
||||
feature-setting-value-pbm:
|
||||
description: An integer either 0 or 1 indicating if cookie banner setting should be enabled or disabled,
|
||||
0 for setting the value to disabled, 1 for enabling the setting with the value reject_all.
|
||||
OnboardingPanel:
|
||||
description: The types of onboarding panels in the onboarding page
|
||||
variants:
|
||||
themes:
|
||||
description: The themes onboarding panel where users pick themes
|
||||
toolbar-placement:
|
||||
description: The onboarding panel where users choose their toolbar placement (bottom or top)
|
||||
sync:
|
||||
description: The onboarding panel where users can sign in to sync
|
||||
tcp:
|
||||
description: The onboarding panel where users can choose their total cookie protection settings
|
||||
privacy-notice:
|
||||
description: The onboarding panel where users can tap to view our privacy notice.
|
@ -1,114 +0,0 @@
|
||||
---
|
||||
features:
|
||||
|
||||
juno-onboarding:
|
||||
description: A feature that shows juno onboarding flow.
|
||||
|
||||
variables:
|
||||
cards:
|
||||
description: Collection of user facing onboarding cards.
|
||||
type: Map<String, OnboardingCardData>
|
||||
default:
|
||||
default-browser:
|
||||
card-type: default-browser
|
||||
title: juno_onboarding_default_browser_title_nimbus_2
|
||||
ordering: 10
|
||||
body: juno_onboarding_default_browser_description_nimbus_2
|
||||
link-text: juno_onboarding_default_browser_description_link_text
|
||||
image-res: ic_onboarding_welcome
|
||||
primary-button-label: juno_onboarding_default_browser_positive_button
|
||||
secondary-button-label: juno_onboarding_default_browser_negative_button
|
||||
|
||||
add-search-widget:
|
||||
card-type: add-search-widget
|
||||
enabled: false
|
||||
title: juno_onboarding_add_search_widget_title
|
||||
body: juno_onboarding_add_search_widget_description
|
||||
image-res: ic_onboarding_search_widget
|
||||
ordering: 15
|
||||
primary-button-label: juno_onboarding_add_search_widget_positive_button
|
||||
secondary-button-label: juno_onboarding_add_search_widget_negative_button
|
||||
|
||||
sync-sign-in:
|
||||
card-type: sync-sign-in
|
||||
title: juno_onboarding_sign_in_title_2
|
||||
body: juno_onboarding_sign_in_description_2
|
||||
image-res: ic_onboarding_sync
|
||||
ordering: 20
|
||||
primary-button-label: juno_onboarding_sign_in_positive_button
|
||||
secondary-button-label: juno_onboarding_sign_in_negative_button
|
||||
|
||||
notification-permission:
|
||||
card-type: notification-permission
|
||||
title: juno_onboarding_enable_notifications_title_nimbus_2
|
||||
body: juno_onboarding_enable_notifications_description_nimbus_2
|
||||
image-res: ic_notification_permission
|
||||
ordering: 30
|
||||
primary-button-label: juno_onboarding_enable_notifications_positive_button
|
||||
secondary-button-label: juno_onboarding_enable_notifications_negative_button
|
||||
|
||||
objects:
|
||||
|
||||
OnboardingCardData:
|
||||
description: An object to describe a user facing onboarding card.
|
||||
fields:
|
||||
card-type:
|
||||
type: OnboardingCardType
|
||||
description: The type of the card.
|
||||
# This should never be defaulted.
|
||||
default: default-browser
|
||||
enabled:
|
||||
type: Boolean
|
||||
description: If true, this card is shown to the user.
|
||||
default: true
|
||||
title:
|
||||
type: Text
|
||||
description: The title text displayed to the user.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
body:
|
||||
type: Text
|
||||
description: The message text displayed to the user. May contain linkable text.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
link-text:
|
||||
type: Option<Text>
|
||||
description: >
|
||||
The text to link from the body text. This should match the linkable text from the body text exactly.
|
||||
e.g. body: This is a policy link
|
||||
link-text: policy link
|
||||
default: null
|
||||
image-res:
|
||||
type: Image
|
||||
description: The resource id of the image to be displayed.
|
||||
# This should never be defaulted.
|
||||
default: ic_onboarding_welcome
|
||||
ordering:
|
||||
type: Int
|
||||
description: Used to sequence the cards.
|
||||
# This should never be defaulted.
|
||||
default: 0
|
||||
primary-button-label:
|
||||
type: Text
|
||||
description: The text to display on the primary button.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
secondary-button-label:
|
||||
type: Text
|
||||
description: The text to display on the secondary button.
|
||||
# This should never be defaulted.
|
||||
default: ""
|
||||
|
||||
enums:
|
||||
|
||||
OnboardingCardType:
|
||||
description: An enum to describe a type of card.
|
||||
variants:
|
||||
default-browser:
|
||||
description: Allows user to set Firefox as the default browser.
|
||||
sync-sign-in:
|
||||
description: Allows user to sync with a Firefox account.
|
||||
notification-permission:
|
||||
description: Allows user to enable notification permission.
|
||||
add-search-widget:
|
||||
description: Allows user to add search widget to homescreen.
|
@ -1,19 +0,0 @@
|
||||
---
|
||||
features:
|
||||
|
||||
private-browsing:
|
||||
description: Private Browsing Mode
|
||||
|
||||
variables:
|
||||
felt-privacy-enabled:
|
||||
description: if true, enable felt privacy related UI
|
||||
type: Boolean
|
||||
default: false
|
||||
|
||||
defaults:
|
||||
- channel: developer
|
||||
value:
|
||||
felt-privacy-enabled: false
|
||||
- channel: nightly
|
||||
value:
|
||||
felt-privacy-enabled: false
|
@ -1,49 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Muted_Video_Test_Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="testContent">Page content: muted video player</p>
|
||||
<div class="playbackState">
|
||||
<p>Media file not playing</p>
|
||||
</div>
|
||||
<div id="video-container" style="text-align:center">
|
||||
<button onclick="play()">Play</button>
|
||||
<button onclick="pause()">Pause</button>
|
||||
<button onclick="fullscreen()">Full Screen</button>
|
||||
<br><br>
|
||||
<video id="mutedVideo" width="420" autoplay muted controls loop>
|
||||
<source src="../resources/clip.mp4" type="video/mp4">
|
||||
Your browser does not support HTML video.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const mutedVideo = document.getElementById("mutedVideo");
|
||||
|
||||
function play() {
|
||||
mutedVideo.play();
|
||||
}
|
||||
|
||||
function pause() {
|
||||
mutedVideo.pause();
|
||||
}
|
||||
|
||||
function fullscreen() {
|
||||
mutedVideo.requestFullscreen();
|
||||
}
|
||||
|
||||
mutedVideo.addEventListener('playing', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is playing";
|
||||
});
|
||||
|
||||
mutedVideo.addEventListener('pause', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is paused";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,49 +1,14 @@
|
||||
<!DOCTYPE HTML>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Video_Test_Page</title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
</head>
|
||||
<body>
|
||||
<p id="testContent">Page content: video player</p>
|
||||
<div class="playbackState">
|
||||
<p>Media file not playing</p>
|
||||
</div>
|
||||
<div id="video-container" style="text-align:center">
|
||||
<button onclick="play()">Play</button>
|
||||
<button onclick="pause()">Pause</button>
|
||||
<button onclick="fullscreen()">Full Screen</button>
|
||||
<br><br>
|
||||
<video id="video" width="420" autoplay controls loop>
|
||||
<source src="../resources/clip.mp4" type="video/mp4">
|
||||
Your browser does not support HTML video.
|
||||
<div id="video-container">
|
||||
<video id="videoSample" width="320" height="240" controls loop>
|
||||
<source src="../resources/clip.mp4">
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const video = document.getElementById("video");
|
||||
|
||||
function play() {
|
||||
video.play();
|
||||
}
|
||||
|
||||
function pause() {
|
||||
video.pause();
|
||||
}
|
||||
|
||||
function fullscreen() {
|
||||
video.requestFullscreen();
|
||||
}
|
||||
|
||||
video.addEventListener('playing', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is playing";
|
||||
});
|
||||
|
||||
video.addEventListener('pause', (event) => {
|
||||
document.querySelector('.playbackState').innerHTML="Media file is paused";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
Binary file not shown.
@ -1,74 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.experimentintegration
|
||||
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||
import org.mozilla.fenix.helpers.TestHelper
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
|
||||
class GenericExperimentIntegrationTest {
|
||||
private val experimentName = "Viewpoint"
|
||||
|
||||
@get:Rule
|
||||
val activityTestRule = HomeActivityTestRule(
|
||||
isJumpBackInCFREnabled = false,
|
||||
isPWAsPromptEnabled = false,
|
||||
isTCPCFREnabled = false,
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
TestHelper.appContext.settings().showSecretDebugMenuThisSession = true
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
TestHelper.appContext.settings().showSecretDebugMenuThisSession = false
|
||||
}
|
||||
|
||||
private fun disableStudiesViaStudiesToggle() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openExperimentsMenu {
|
||||
verifyExperimentEnrolled(experimentName)
|
||||
}.goBack {
|
||||
}.openSettingsSubMenuDataCollection {
|
||||
clickStudiesOption()
|
||||
verifyStudiesToggle(true)
|
||||
clickStudiesToggle()
|
||||
clickStudiesDialogOkButton()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExperimentUnenrolled() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openExperimentsMenu {
|
||||
verifyExperimentExists(experimentName)
|
||||
verifyExperimentNotEnrolled(experimentName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExperimentUnenrolledViaSecretMenu() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openExperimentsMenu {
|
||||
verifyExperimentExists(experimentName)
|
||||
verifyExperimentEnrolled(experimentName)
|
||||
unenrollfromExperiment(experimentName)
|
||||
verifyExperimentNotEnrolled(experimentName)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pytest = "*"
|
||||
pytest-html = "*"
|
||||
pytest-metadata = "*"
|
||||
pytest-variables = "*"
|
||||
pyyaml = "*"
|
||||
requests = "*"
|
||||
|
||||
[dev-packages]
|
||||
black = "*"
|
||||
flake8 = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.11"
|
@ -1,445 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "53501c7e751ae79697bf8c7289b6095f49fed97242fe186fea42989e800c39d5"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.11"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
|
||||
"sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2023.7.22"
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843",
|
||||
"sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786",
|
||||
"sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e",
|
||||
"sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8",
|
||||
"sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4",
|
||||
"sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa",
|
||||
"sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d",
|
||||
"sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82",
|
||||
"sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7",
|
||||
"sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895",
|
||||
"sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d",
|
||||
"sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a",
|
||||
"sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382",
|
||||
"sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678",
|
||||
"sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b",
|
||||
"sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e",
|
||||
"sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741",
|
||||
"sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4",
|
||||
"sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596",
|
||||
"sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9",
|
||||
"sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69",
|
||||
"sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c",
|
||||
"sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77",
|
||||
"sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13",
|
||||
"sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459",
|
||||
"sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e",
|
||||
"sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7",
|
||||
"sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908",
|
||||
"sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a",
|
||||
"sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f",
|
||||
"sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8",
|
||||
"sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482",
|
||||
"sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d",
|
||||
"sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d",
|
||||
"sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545",
|
||||
"sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34",
|
||||
"sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86",
|
||||
"sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6",
|
||||
"sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe",
|
||||
"sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e",
|
||||
"sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc",
|
||||
"sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7",
|
||||
"sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd",
|
||||
"sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c",
|
||||
"sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557",
|
||||
"sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a",
|
||||
"sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89",
|
||||
"sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078",
|
||||
"sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e",
|
||||
"sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4",
|
||||
"sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403",
|
||||
"sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0",
|
||||
"sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89",
|
||||
"sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115",
|
||||
"sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9",
|
||||
"sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05",
|
||||
"sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a",
|
||||
"sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec",
|
||||
"sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56",
|
||||
"sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38",
|
||||
"sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479",
|
||||
"sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c",
|
||||
"sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e",
|
||||
"sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd",
|
||||
"sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186",
|
||||
"sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455",
|
||||
"sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c",
|
||||
"sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65",
|
||||
"sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78",
|
||||
"sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287",
|
||||
"sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df",
|
||||
"sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43",
|
||||
"sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1",
|
||||
"sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7",
|
||||
"sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989",
|
||||
"sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a",
|
||||
"sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63",
|
||||
"sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884",
|
||||
"sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649",
|
||||
"sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810",
|
||||
"sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828",
|
||||
"sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4",
|
||||
"sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2",
|
||||
"sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd",
|
||||
"sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5",
|
||||
"sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe",
|
||||
"sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293",
|
||||
"sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e",
|
||||
"sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e",
|
||||
"sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"
|
||||
],
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.3.0"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
|
||||
"sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.4"
|
||||
},
|
||||
"iniconfig": {
|
||||
"hashes": [
|
||||
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
|
||||
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
|
||||
"sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.1.2"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e",
|
||||
"sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e",
|
||||
"sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431",
|
||||
"sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686",
|
||||
"sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c",
|
||||
"sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559",
|
||||
"sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc",
|
||||
"sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb",
|
||||
"sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939",
|
||||
"sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c",
|
||||
"sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0",
|
||||
"sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4",
|
||||
"sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9",
|
||||
"sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575",
|
||||
"sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba",
|
||||
"sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d",
|
||||
"sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd",
|
||||
"sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3",
|
||||
"sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00",
|
||||
"sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155",
|
||||
"sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac",
|
||||
"sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52",
|
||||
"sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f",
|
||||
"sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8",
|
||||
"sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b",
|
||||
"sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007",
|
||||
"sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24",
|
||||
"sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea",
|
||||
"sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198",
|
||||
"sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0",
|
||||
"sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee",
|
||||
"sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be",
|
||||
"sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2",
|
||||
"sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1",
|
||||
"sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707",
|
||||
"sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6",
|
||||
"sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c",
|
||||
"sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58",
|
||||
"sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823",
|
||||
"sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779",
|
||||
"sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636",
|
||||
"sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c",
|
||||
"sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad",
|
||||
"sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee",
|
||||
"sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc",
|
||||
"sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2",
|
||||
"sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48",
|
||||
"sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7",
|
||||
"sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e",
|
||||
"sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b",
|
||||
"sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa",
|
||||
"sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5",
|
||||
"sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e",
|
||||
"sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb",
|
||||
"sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9",
|
||||
"sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57",
|
||||
"sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc",
|
||||
"sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc",
|
||||
"sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2",
|
||||
"sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.1.3"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
|
||||
"sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==23.2"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12",
|
||||
"sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:2f2301e797521b23e4d2585a0a3d7b5e50fdddaaf7e7d6773ea26ddb17c213ab",
|
||||
"sha256:460c9a59b14e27c602eb5ece2e47bec99dc5fc5f6513cf924a7d03a578991b1f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==7.4.1"
|
||||
},
|
||||
"pytest-html": {
|
||||
"hashes": [
|
||||
"sha256:3b473cc278272f8b5a34cd3bf10f88ac5fcb17cb5af22f9323514af00c310e64",
|
||||
"sha256:79c4677ed6196417bf290d8b81f706342ae49f726f623728efa3f7dfff09f8eb"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==4.0.0"
|
||||
},
|
||||
"pytest-metadata": {
|
||||
"hashes": [
|
||||
"sha256:769a9c65d2884bd583bc626b0ace77ad15dbe02dd91a9106d47fd46d9c2569ca",
|
||||
"sha256:a17b1e40080401dc23177599208c52228df463db191c1a573ccdffacd885e190"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"pytest-variables": {
|
||||
"hashes": [
|
||||
"sha256:190d9d4da5a6013eb02df2049f6047d911cdbe44c5b1734a6acc1748433c93d0",
|
||||
"sha256:ab84235417afac5a0a7dd4c3918287d9c7329d2e16d570d6e943f8d8e02533b9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5",
|
||||
"sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc",
|
||||
"sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df",
|
||||
"sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741",
|
||||
"sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206",
|
||||
"sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27",
|
||||
"sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595",
|
||||
"sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62",
|
||||
"sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98",
|
||||
"sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696",
|
||||
"sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290",
|
||||
"sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9",
|
||||
"sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d",
|
||||
"sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6",
|
||||
"sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867",
|
||||
"sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47",
|
||||
"sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486",
|
||||
"sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6",
|
||||
"sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3",
|
||||
"sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007",
|
||||
"sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938",
|
||||
"sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0",
|
||||
"sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c",
|
||||
"sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735",
|
||||
"sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d",
|
||||
"sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28",
|
||||
"sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4",
|
||||
"sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba",
|
||||
"sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8",
|
||||
"sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5",
|
||||
"sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd",
|
||||
"sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3",
|
||||
"sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0",
|
||||
"sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515",
|
||||
"sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c",
|
||||
"sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c",
|
||||
"sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924",
|
||||
"sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34",
|
||||
"sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43",
|
||||
"sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859",
|
||||
"sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673",
|
||||
"sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54",
|
||||
"sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a",
|
||||
"sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b",
|
||||
"sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab",
|
||||
"sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa",
|
||||
"sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c",
|
||||
"sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585",
|
||||
"sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d",
|
||||
"sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==6.0.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
|
||||
"sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.31.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84",
|
||||
"sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.0.7"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"black": {
|
||||
"hashes": [
|
||||
"sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3",
|
||||
"sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb",
|
||||
"sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087",
|
||||
"sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320",
|
||||
"sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6",
|
||||
"sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3",
|
||||
"sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc",
|
||||
"sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f",
|
||||
"sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587",
|
||||
"sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91",
|
||||
"sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a",
|
||||
"sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad",
|
||||
"sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926",
|
||||
"sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9",
|
||||
"sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be",
|
||||
"sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd",
|
||||
"sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96",
|
||||
"sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491",
|
||||
"sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2",
|
||||
"sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a",
|
||||
"sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f",
|
||||
"sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==23.7.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
|
||||
"sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==8.1.7"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23",
|
||||
"sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_full_version >= '3.8.1'",
|
||||
"version": "==6.1.0"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
|
||||
"sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"mypy-extensions": {
|
||||
"hashes": [
|
||||
"sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d",
|
||||
"sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5",
|
||||
"sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==23.2"
|
||||
},
|
||||
"pathspec": {
|
||||
"hashes": [
|
||||
"sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20",
|
||||
"sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.11.2"
|
||||
},
|
||||
"platformdirs": {
|
||||
"hashes": [
|
||||
"sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3",
|
||||
"sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.11.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f",
|
||||
"sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.11.1"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774",
|
||||
"sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==3.1.0"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.experimentintegration
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||
import org.mozilla.fenix.helpers.TestHelper
|
||||
import org.mozilla.fenix.ui.robots.browserScreen
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
|
||||
/**
|
||||
* Tests for verifying functionality of the message survey surface
|
||||
*/
|
||||
class SurveyExperimentIntegrationTest {
|
||||
private val surveyURL = "qsurvey.mozilla.com"
|
||||
private val experimentName = "Viewpoint"
|
||||
|
||||
@get:Rule
|
||||
val activityTestRule = HomeActivityTestRule(
|
||||
isJumpBackInCFREnabled = false,
|
||||
isPWAsPromptEnabled = false,
|
||||
isTCPCFREnabled = false,
|
||||
isDeleteSitePermissionsEnabled = true,
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
TestHelper.appContext.settings().showSecretDebugMenuThisSession = true
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
TestHelper.appContext.settings().showSecretDebugMenuThisSession = false
|
||||
}
|
||||
|
||||
fun checkExperimentExists() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openExperimentsMenu {
|
||||
verifyExperimentExists(experimentName)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSurveyNavigatesCorrectly() {
|
||||
browserScreen {
|
||||
verifySurveyButton()
|
||||
}.clickSurveyButton {
|
||||
verifyUrl(surveyURL)
|
||||
}
|
||||
|
||||
checkExperimentExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSurveyNoThanksNavigatesCorrectly() {
|
||||
browserScreen {
|
||||
verifySurveyNoThanksButton()
|
||||
}.clickNoThanksSurveyButton {
|
||||
verifyTabCounter("0")
|
||||
}
|
||||
|
||||
checkExperimentExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkHomescreenSurveyDismissesCorrectly() {
|
||||
browserScreen {
|
||||
verifyHomeScreenSurveyCloseButton()
|
||||
}.clickHomeScreenSurveyCloseButton {
|
||||
verifyTabCounter("0")
|
||||
verifySurveyButtonDoesNotExist()
|
||||
}
|
||||
|
||||
checkExperimentExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSurveyLandscapeLooksCorrect() {
|
||||
activityTestRule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
browserScreen {
|
||||
verifySurveyNoThanksButton()
|
||||
verifySurveyButton()
|
||||
}
|
||||
|
||||
checkExperimentExists()
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
from experimentintegration.gradlewbuild import GradlewBuild
|
||||
|
||||
KLAATU_SERVER_URL = "http://localhost:1378"
|
||||
KLAATU_LOCAL_SERVER_URL = "http://localhost:1378"
|
||||
|
||||
here = Path()
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--experiment", action="store", help="The experiments experimenter URL"
|
||||
)
|
||||
parser.addoption(
|
||||
"--stage", action="store_true", default=None, help="Use the stage server"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(name="load_branches")
|
||||
def fixture_load_branches(experiment_url):
|
||||
branches = []
|
||||
|
||||
if experiment_url:
|
||||
data = experiment_url
|
||||
else:
|
||||
try:
|
||||
data = requests.get(f"{KLAATU_SERVER_URL}/experiment").json()
|
||||
except ConnectionRefusedError:
|
||||
logging.warn("No URL or experiment slug provided, exiting.")
|
||||
exit()
|
||||
else:
|
||||
for item in reversed(data):
|
||||
data = item
|
||||
break
|
||||
experiment = requests.get(data).json()
|
||||
for item in experiment["branches"]:
|
||||
branches.append(item["slug"])
|
||||
return branches
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gradlewbuild_log(pytestconfig, tmpdir):
|
||||
gradlewbuild_log = f"{tmpdir.join('gradlewbuild.log')}"
|
||||
pytestconfig._gradlewbuild_log = gradlewbuild_log
|
||||
yield gradlewbuild_log
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gradlewbuild(gradlewbuild_log):
|
||||
yield GradlewBuild(gradlewbuild_log)
|
||||
|
||||
|
||||
@pytest.fixture(name="experiment_data")
|
||||
def fixture_experiment_data(experiment_url):
|
||||
data = requests.get(experiment_url).json()
|
||||
for item in data["branches"][0]["features"][0]["value"]["messages"].values():
|
||||
item["surface"] = "homescreen"
|
||||
item["style"] = "URGENT"
|
||||
for count, trigger in enumerate(item["trigger"]):
|
||||
if "USER_EN_SPEAKER" not in trigger:
|
||||
del(item["trigger"][count])
|
||||
return [data]
|
||||
|
||||
|
||||
@pytest.fixture(name="experiment_url", scope="module")
|
||||
def fixture_experiment_url(request, variables):
|
||||
url = None
|
||||
|
||||
if slug := request.config.getoption("--experiment"):
|
||||
# Build URL from slug
|
||||
if request.config.getoption("--stage"):
|
||||
url = f"{variables['urls']['stage_server']}/api/v6/experiments/{slug}"
|
||||
else:
|
||||
url = f"{variables['urls']['prod_server']}/api/v6/experiments/{slug}"
|
||||
else:
|
||||
try:
|
||||
data = requests.get(f"{KLAATU_SERVER_URL}/experiment").json()
|
||||
except requests.exceptions.ConnectionError:
|
||||
logging.error("No URL or experiment slug provided, exiting.")
|
||||
exit()
|
||||
else:
|
||||
for item in data:
|
||||
if isinstance(item, dict):
|
||||
continue
|
||||
else:
|
||||
url = item
|
||||
yield url
|
||||
return_data = {"url": url}
|
||||
try:
|
||||
requests.put(f"{KLAATU_SERVER_URL}/experiment", json=return_data)
|
||||
except requests.exceptions.ConnectionError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture(name="json_data")
|
||||
def fixture_json_data(tmp_path, experiment_data):
|
||||
path = tmp_path / "data"
|
||||
path.mkdir()
|
||||
json_path = path / "data.json"
|
||||
with open(json_path, "w", encoding="utf-8") as f:
|
||||
# URL of experiment/klaatu server
|
||||
data = {"data": experiment_data}
|
||||
json.dump(data, f)
|
||||
return json_path
|
||||
|
||||
|
||||
@pytest.fixture(name="experiment_slug")
|
||||
def fixture_experiment_slug(experiment_data):
|
||||
return experiment_data[0]["slug"]
|
||||
|
||||
|
||||
@pytest.fixture(name="start_app")
|
||||
def fixture_start_app():
|
||||
def _():
|
||||
command = f"nimbus-cli --app fenix --channel developer open"
|
||||
try:
|
||||
out = subprocess.check_output(
|
||||
command,
|
||||
cwd=os.path.join(here, os.pardir),
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
shell=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
out = e.output
|
||||
raise
|
||||
finally:
|
||||
with open(gradlewbuild_log, "w") as f:
|
||||
f.write(out)
|
||||
time.sleep(
|
||||
15
|
||||
) # Wait a while as there's no real way to know when the app has started
|
||||
|
||||
return _
|
||||
|
||||
|
||||
@pytest.fixture(name="send_test_results", autouse=True)
|
||||
def fixture_send_test_results():
|
||||
yield
|
||||
here = Path()
|
||||
|
||||
with open(f"{here.resolve()}/results/index.html", "rb") as f:
|
||||
files = {"file": f}
|
||||
try:
|
||||
requests.post(f"{KLAATU_SERVER_URL}/test_results", files=files)
|
||||
except requests.exceptions.ConnectionError:
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture(name="setup_experiment")
|
||||
def fixture_setup_experiment(experiment_slug, json_data, gradlewbuild_log):
|
||||
def _(branch):
|
||||
logging.info(f"Testing experiment {experiment_slug}, BRANCH: {branch[0]}")
|
||||
command = f"nimbus-cli --app fenix --channel developer enroll {experiment_slug} --branch {branch[0]} --file {json_data} --reset-app"
|
||||
logging.info(f"Running command {command}")
|
||||
try:
|
||||
out = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
out = e.output
|
||||
raise
|
||||
finally:
|
||||
with open(gradlewbuild_log, "w") as f:
|
||||
f.write(f"{out}")
|
||||
time.sleep(
|
||||
15
|
||||
) # Wait a while as there's no real way to know when the app has started
|
||||
|
||||
return _
|
@ -1,45 +0,0 @@
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from syncintegration.adbrun import ADBrun
|
||||
|
||||
here = os.path.dirname(__file__)
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
class GradlewBuild(object):
|
||||
binary = "./gradlew"
|
||||
logger = logging.getLogger()
|
||||
adbrun = ADBrun()
|
||||
|
||||
def __init__(self, log):
|
||||
self.log = log
|
||||
|
||||
def test(self, identifier):
|
||||
# self.adbrun.launch()
|
||||
|
||||
# Change path accordingly to go to root folder to run gradlew
|
||||
os.chdir("../../../../../../../..")
|
||||
cmd = f"adb shell am instrument -w -e class org.mozilla.fenix.experimentintegration.{identifier} org.mozilla.fenix.debug.test/androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
self.logger.info("Running cmd: {}".format(cmd))
|
||||
|
||||
out = ""
|
||||
try:
|
||||
out = subprocess.check_output(
|
||||
cmd, encoding="utf8", shell=True, stderr=subprocess.STDOUT
|
||||
)
|
||||
if "FAILURES" in out:
|
||||
raise (AssertionError(out))
|
||||
except subprocess.CalledProcessError as e:
|
||||
out = e.output
|
||||
raise
|
||||
finally:
|
||||
# Set the path correctly
|
||||
tests_path = (
|
||||
"app/src/androidTest/java/org/mozilla/fenix/experimentintegration/"
|
||||
)
|
||||
os.chdir(tests_path)
|
||||
with open(self.log, "w") as f:
|
||||
f.write(str(out))
|
@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
echo "Waiting emulator is ready..."
|
||||
~/Library/Android/sdk/emulator/emulator -avd Pixel_3_API_28 -wipe-data -no-boot-anim -screen no-touch &
|
||||
|
||||
bootanim=""
|
||||
failcounter=0
|
||||
timeout_in_sec=360
|
||||
|
||||
until [[ "$bootanim" =~ "stopped" ]]; do
|
||||
bootanim=`~/Library/Android/sdk/platform-tools/adb -e shell getprop init.svc.bootanim 2>&1 &`
|
||||
if [[ "$bootanim" =~ "device not found" || "$bootanim" =~ "device offline"
|
||||
|| "$bootanim" =~ "running" ]]; then
|
||||
let "failcounter += 1"
|
||||
echo "Waiting for emulator to start"
|
||||
if [[ $failcounter -gt timeout_in_sec ]]; then
|
||||
echo "Timeout ($timeout_in_sec seconds) reached; failed to start emulator"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Emulator is ready"
|
||||
sleep 10
|
@ -1,4 +0,0 @@
|
||||
[pytest]
|
||||
addopts = --verbose --html=results/index.html --self-contained-html --variables=variables.yaml
|
||||
log_cli = true
|
||||
log_cli_level = info
|
@ -1,12 +0,0 @@
|
||||
import pytest
|
||||
|
||||
@pytest.mark.parametrize("load_branches", [("branch")], indirect=True)
|
||||
def test_experiment_unenrolls_via_studies_toggle(setup_experiment, gradlewbuild, load_branches):
|
||||
setup_experiment(load_branches)
|
||||
gradlewbuild.test("GenericExperimentIntegrationTest#disableStudiesViaStudiesToggle")
|
||||
gradlewbuild.test("GenericExperimentIntegrationTest#testExperimentUnenrolls")
|
||||
|
||||
@pytest.mark.parametrize("load_branches", [("branch")], indirect=True)
|
||||
def test_experiment_unenrolls_via_secret_menu(setup_experiment, gradlewbuild, load_branches):
|
||||
setup_experiment(load_branches)
|
||||
gradlewbuild.test("GenericExperimentIntegrationTest#testExperimentUnenrollsViaSecretMenu")
|
@ -1,22 +0,0 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("load_branches", [("branch")], indirect=True)
|
||||
def test_survey_navigates_correctly(setup_experiment, gradlewbuild, load_branches):
|
||||
setup_experiment(load_branches)
|
||||
gradlewbuild.test("SurveyExperimentIntegrationTest#checkSurveyNavigatesCorrectly")
|
||||
|
||||
@pytest.mark.parametrize("load_branches", [("branch")], indirect=True)
|
||||
def test_survey_no_thanks_navigates_correctly(setup_experiment, gradlewbuild, load_branches):
|
||||
setup_experiment(load_branches)
|
||||
gradlewbuild.test("SurveyExperimentIntegrationTest#checkSurveyNoThanksNavigatesCorrectly")
|
||||
|
||||
@pytest.mark.parametrize("load_branches", [("branch")], indirect=True)
|
||||
def test_homescreen_survey_dismisses_correctly(setup_experiment, gradlewbuild, load_branches):
|
||||
setup_experiment(load_branches)
|
||||
gradlewbuild.test("SurveyExperimentIntegrationTest#checkHomescreenSurveyDismissesCorrectly")
|
||||
|
||||
@pytest.mark.parametrize("load_branches", [("branch")], indirect=True)
|
||||
def test_survey_landscape_looks_correct(setup_experiment, gradlewbuild, load_branches):
|
||||
setup_experiment(load_branches)
|
||||
gradlewbuild.test("SurveyExperimentIntegrationTest#checkSurveyLandscapeLooksCorrect")
|
@ -1,3 +0,0 @@
|
||||
urls:
|
||||
stage_server: "https://stage.experimenter.nonprod.dataops.mozgcp.net"
|
||||
prod_server: "https://experimenter.services.mozilla.com"
|
@ -1,75 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.extensions
|
||||
|
||||
import android.content.Context
|
||||
import mozilla.components.concept.engine.EngineSession
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mozilla.experiments.nimbus.HardcodedNimbusFeatures
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.gecko.GeckoProvider
|
||||
import org.mozilla.fenix.helpers.TestHelper
|
||||
import org.mozilla.fenix.nimbus.FxNimbus
|
||||
|
||||
/**
|
||||
* Instrumentation test for verifying that the extensions process can be controlled with Nimbus.
|
||||
*/
|
||||
class ExtensionProcessTest {
|
||||
private lateinit var context: Context
|
||||
private lateinit var policy: EngineSession.TrackingProtectionPolicy
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
context = TestHelper.appContext
|
||||
policy =
|
||||
context.components.core.trackingProtectionPolicyFactory.createTrackingProtectionPolicy()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_extension_process_can_be_enabled_by_nimbus() {
|
||||
val hardcodedNimbus = HardcodedNimbusFeatures(
|
||||
context,
|
||||
"extensions-process" to JSONObject(
|
||||
"""
|
||||
{
|
||||
"enabled": true
|
||||
}
|
||||
""".trimIndent(),
|
||||
),
|
||||
)
|
||||
|
||||
hardcodedNimbus.connectWith(FxNimbus)
|
||||
|
||||
val runtime = GeckoProvider.createRuntimeSettings(context, policy)
|
||||
|
||||
assertTrue(FxNimbus.features.extensionsProcess.value().enabled)
|
||||
assertTrue(runtime.extensionsProcessEnabled!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_extension_process_can_be_disabled_by_nimbus() {
|
||||
val hardcodedNimbus = HardcodedNimbusFeatures(
|
||||
context,
|
||||
"extensions-process" to JSONObject(
|
||||
"""
|
||||
{
|
||||
"enabled": false
|
||||
}
|
||||
""".trimIndent(),
|
||||
),
|
||||
)
|
||||
|
||||
hardcodedNimbus.connectWith(FxNimbus)
|
||||
|
||||
val runtime = GeckoProvider.createRuntimeSettings(context, policy)
|
||||
|
||||
assertFalse(FxNimbus.features.extensionsProcess.value().enabled)
|
||||
assertFalse(runtime.extensionsProcessEnabled!!)
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.helpers
|
||||
|
||||
import android.content.Context
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import mozilla.appservices.places.BookmarkRoot
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.browser.icons.generator.DefaultIconGenerator
|
||||
import mozilla.components.browser.state.search.SearchEngine
|
||||
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
|
||||
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
||||
import mozilla.components.concept.storage.PageVisit
|
||||
import mozilla.components.concept.storage.VisitType
|
||||
import mozilla.components.feature.search.ext.createSearchEngine
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.helpers.TestHelper.appContext
|
||||
import org.mozilla.fenix.search.SearchEngineSource.None.searchEngine
|
||||
|
||||
object MockBrowserDataHelper {
|
||||
val context: Context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
|
||||
/**
|
||||
* Adds a new bookmark item, visible in the Bookmarks folder.
|
||||
*
|
||||
* @param url The URL of the bookmark item to add. URLs should use the "https://example.com" format.
|
||||
* @param title The title of the bookmark item to add.
|
||||
* @param position Example for the position param: 1u, 2u, etc.
|
||||
*/
|
||||
fun createBookmarkItem(url: String, title: String, position: UInt?) {
|
||||
runBlocking {
|
||||
PlacesBookmarksStorage(context)
|
||||
.addItem(
|
||||
BookmarkRoot.Mobile.id,
|
||||
url,
|
||||
title,
|
||||
position,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new history item, visible in the History folder.
|
||||
*
|
||||
* @param url The URL of the history item to add. URLs should use the "https://example.com" format.
|
||||
*/
|
||||
fun createHistoryItem(url: String) {
|
||||
runBlocking {
|
||||
PlacesHistoryStorage(appContext)
|
||||
.recordVisit(
|
||||
url,
|
||||
PageVisit(VisitType.LINK),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tab with a webpage, also visible in the History folder.
|
||||
*
|
||||
* URLs should use the "https://example.com" format.
|
||||
*/
|
||||
fun createTabItem(url: String) {
|
||||
runBlocking {
|
||||
appContext.components.useCases.tabsUseCases.addTab(url)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a search for the provided search term in a new tab.
|
||||
*
|
||||
*/
|
||||
fun createSearchHistory(searchTerm: String) {
|
||||
appContext.components.useCases.searchUseCases.newTabSearch.invoke(searchTerm)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new custom search engine object.
|
||||
*
|
||||
* @param mockWebServer The mockWebServer instance.
|
||||
* @param searchEngineName The name of the new search engine.
|
||||
*/
|
||||
private fun createCustomSearchEngine(mockWebServer: MockWebServer, searchEngineName: String): SearchEngine {
|
||||
val searchString =
|
||||
"http://localhost:${mockWebServer.port}/pages/searchResults.html?search={searchTerms}"
|
||||
return createSearchEngine(
|
||||
name = searchEngineName,
|
||||
url = searchString,
|
||||
icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new custom search engine to the apps Search Engines list.
|
||||
*
|
||||
* @param searchEngine Use createCustomSearchEngine method to create one.
|
||||
*/
|
||||
fun addCustomSearchEngine(mockWebServer: MockWebServer, searchEngineName: String) {
|
||||
val searchEngine = createCustomSearchEngine(mockWebServer, searchEngineName)
|
||||
|
||||
appContext.components.useCases.searchUseCases.addSearchEngine(searchEngine)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds and selects as default a new custom search engine to the apps Search Engines list.
|
||||
*
|
||||
* @param searchEngine Use createCustomSearchEngine method to create one.
|
||||
*/
|
||||
fun setCustomSearchEngine(mockWebServer: MockWebServer, searchEngineName: String) {
|
||||
val searchEngine = createCustomSearchEngine(mockWebServer, searchEngineName)
|
||||
|
||||
with(appContext.components.useCases.searchUseCases) {
|
||||
addSearchEngine(searchEngine)
|
||||
selectSearchEngine(searchEngine)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.onboarding.view
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.experiments.nimbus.StringHolder
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.nimbus.OnboardingCardData
|
||||
import org.mozilla.fenix.nimbus.OnboardingCardType
|
||||
|
||||
class JunoOnboardingMapperTest {
|
||||
|
||||
@get:Rule
|
||||
val activityTestRule =
|
||||
HomeActivityIntentTestRule.withDefaultSettingsOverrides(skipOnboarding = true)
|
||||
|
||||
@Test
|
||||
fun showNotificationTrue_showAddWidgetFalse_pagesToDisplay_returnsSortedListOfAllConvertedPages_withoutAddWidgetPage() {
|
||||
val expected = listOf(defaultBrowserPageUiData, syncPageUiData, notificationPageUiData)
|
||||
assertEquals(expected, unsortedAllKnownCardData.toPageUiData(true, false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showNotificationFalse_showAddWidgetFalse_pagesToDisplay_returnsSortedListOfConvertedPages_withoutNotificationPage_and_addWidgetPage() {
|
||||
val expected = listOf(defaultBrowserPageUiData, syncPageUiData)
|
||||
assertEquals(expected, unsortedAllKnownCardData.toPageUiData(false, false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showNotificationFalse_showAddWidgetTrue_pagesToDisplay_returnsSortedListOfAllConvertedPages_withoutNotificationPage() {
|
||||
val expected = listOf(defaultBrowserPageUiData, addSearchWidgetPageUiData, syncPageUiData)
|
||||
assertEquals(expected, unsortedAllKnownCardData.toPageUiData(false, true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showNotificationTrue_and_showAddWidgetTrue_pagesToDisplay_returnsSortedListOfConvertedPages() {
|
||||
val expected = listOf(defaultBrowserPageUiData, addSearchWidgetPageUiData, syncPageUiData, notificationPageUiData)
|
||||
assertEquals(expected, unsortedAllKnownCardData.toPageUiData(true, true))
|
||||
}
|
||||
}
|
||||
|
||||
private val defaultBrowserPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.DEFAULT_BROWSER,
|
||||
imageRes = R.drawable.ic_onboarding_welcome,
|
||||
title = "default browser title",
|
||||
description = "default browser body with link text",
|
||||
linkText = "link text",
|
||||
primaryButtonLabel = "default browser primary button text",
|
||||
secondaryButtonLabel = "default browser secondary button text",
|
||||
)
|
||||
private val addSearchWidgetPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.ADD_SEARCH_WIDGET,
|
||||
imageRes = R.drawable.ic_onboarding_search_widget,
|
||||
title = "add search widget title",
|
||||
description = "add search widget body with link text",
|
||||
linkText = "link text",
|
||||
primaryButtonLabel = "add search widget primary button text",
|
||||
secondaryButtonLabel = "add search widget secondary button text",
|
||||
)
|
||||
private val syncPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.SYNC_SIGN_IN,
|
||||
imageRes = R.drawable.ic_onboarding_sync,
|
||||
title = "sync title",
|
||||
description = "sync body",
|
||||
primaryButtonLabel = "sync primary button text",
|
||||
secondaryButtonLabel = "sync secondary button text",
|
||||
)
|
||||
private val notificationPageUiData = OnboardingPageUiData(
|
||||
type = OnboardingPageUiData.Type.NOTIFICATION_PERMISSION,
|
||||
imageRes = R.drawable.ic_notification_permission,
|
||||
title = "notification title",
|
||||
description = "notification body",
|
||||
primaryButtonLabel = "notification primary button text",
|
||||
secondaryButtonLabel = "notification secondary button text",
|
||||
)
|
||||
|
||||
private val defaultBrowserCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.DEFAULT_BROWSER,
|
||||
imageRes = R.drawable.ic_onboarding_welcome,
|
||||
title = StringHolder(null, "default browser title"),
|
||||
body = StringHolder(null, "default browser body with link text"),
|
||||
linkText = StringHolder(null, "link text"),
|
||||
primaryButtonLabel = StringHolder(null, "default browser primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "default browser secondary button text"),
|
||||
ordering = 10,
|
||||
)
|
||||
private val addSearchWidgetCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.ADD_SEARCH_WIDGET,
|
||||
imageRes = R.drawable.ic_onboarding_search_widget,
|
||||
title = StringHolder(null, "add search widget title"),
|
||||
body = StringHolder(null, "add search widget body with link text"),
|
||||
linkText = StringHolder(null, "link text"),
|
||||
primaryButtonLabel = StringHolder(null, "add search widget primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "add search widget secondary button text"),
|
||||
ordering = 15,
|
||||
)
|
||||
private val syncCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.SYNC_SIGN_IN,
|
||||
imageRes = R.drawable.ic_onboarding_sync,
|
||||
title = StringHolder(null, "sync title"),
|
||||
body = StringHolder(null, "sync body"),
|
||||
primaryButtonLabel = StringHolder(null, "sync primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "sync secondary button text"),
|
||||
ordering = 20,
|
||||
)
|
||||
private val notificationCardData = OnboardingCardData(
|
||||
cardType = OnboardingCardType.NOTIFICATION_PERMISSION,
|
||||
imageRes = R.drawable.ic_notification_permission,
|
||||
title = StringHolder(null, "notification title"),
|
||||
body = StringHolder(null, "notification body"),
|
||||
primaryButtonLabel = StringHolder(null, "notification primary button text"),
|
||||
secondaryButtonLabel = StringHolder(null, "notification secondary button text"),
|
||||
ordering = 30,
|
||||
)
|
||||
|
||||
private val unsortedAllKnownCardData = listOf(
|
||||
syncCardData,
|
||||
notificationCardData,
|
||||
defaultBrowserCardData,
|
||||
addSearchWidgetCardData,
|
||||
)
|
@ -1,189 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.mozilla.fenix.screenshots
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.uiautomator.UiDevice
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityTestRule
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.ui.robots.bookmarksMenu
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
import org.mozilla.fenix.ui.robots.swipeToBottom
|
||||
import tools.fastlane.screengrab.Screengrab
|
||||
import tools.fastlane.screengrab.locale.LocaleTestRule
|
||||
|
||||
class ComposeMenuScreenShotTest : ScreenshotTest() {
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
private lateinit var mDevice: UiDevice
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val localeTestRule = LocaleTestRule()
|
||||
|
||||
@get:Rule
|
||||
val composeTestRule =
|
||||
AndroidComposeTestRule(
|
||||
HomeActivityTestRule.withDefaultSettingsOverrides(
|
||||
tabsTrayRewriteEnabled = true,
|
||||
),
|
||||
) { it.activity }
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
composeTestRule.activity.finishAndRemoveTask()
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun threeDotMenuTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
Screengrab.screenshot("ThreeDotMenuMainRobot_three-dot-menu")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun settingsTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
Screengrab.screenshot("SettingsRobot_settings-menu")
|
||||
}.openTurnOnSyncMenu {
|
||||
Screengrab.screenshot("AccountSettingsRobot_settings-account")
|
||||
}.goBack {
|
||||
}.openSearchSubMenu {
|
||||
Screengrab.screenshot("SettingsSubMenuSearchRobot_settings-search")
|
||||
}.goBack {
|
||||
}.openCustomizeSubMenu {
|
||||
Screengrab.screenshot("SettingsSubMenuThemeRobot_settings-theme")
|
||||
}.goBack {
|
||||
}.openAccessibilitySubMenu {
|
||||
Screengrab.screenshot("SettingsSubMenuAccessibilityRobot_settings-accessibility")
|
||||
}.goBack {
|
||||
}.openLanguageSubMenu {
|
||||
Screengrab.screenshot("SettingsSubMenuAccessibilityRobot_settings-language")
|
||||
}.goBack {
|
||||
// From about here we need to scroll up to ensure all settings options are visible.
|
||||
}.openSetDefaultBrowserSubMenu {
|
||||
Screengrab.screenshot("SettingsSubMenuDefaultBrowserRobot_settings-default-browser")
|
||||
}.goBack {
|
||||
// Disabled for Pixel 2
|
||||
// }.openEnhancedTrackingProtectionSubMenu {
|
||||
// Screengrab.screenshot("settings-enhanced-tp")
|
||||
// }.goBack {
|
||||
}.openLoginsAndPasswordSubMenu {
|
||||
Screengrab.screenshot("SettingsSubMenuLoginsAndPasswords-settings-logins-passwords")
|
||||
}.goBack {
|
||||
swipeToBottom()
|
||||
Screengrab.screenshot("SettingsRobot_settings-scroll-to-bottom")
|
||||
}.openSettingsSubMenuDataCollection {
|
||||
Screengrab.screenshot("settings-telemetry")
|
||||
}.goBack {
|
||||
}.openAddonsManagerMenu {
|
||||
Screengrab.screenshot("settings-addons")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun historyTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}
|
||||
openHistoryThreeDotMenu()
|
||||
Screengrab.screenshot("HistoryRobot_history-menu")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bookmarksManagementTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}
|
||||
openBookmarksThreeDotMenu()
|
||||
Screengrab.screenshot("BookmarksRobot_bookmarks-menu")
|
||||
bookmarksMenu {
|
||||
clickAddFolderButtonUsingId()
|
||||
Screengrab.screenshot("BookmarksRobot_add-folder-view")
|
||||
saveNewFolder()
|
||||
Screengrab.screenshot("BookmarksRobot_error-empty-folder-name")
|
||||
addNewFolderName("test")
|
||||
saveNewFolder()
|
||||
}.openThreeDotMenu("test") {
|
||||
Screengrab.screenshot("ThreeDotMenuBookmarksRobot_folder-menu")
|
||||
}
|
||||
editBookmarkFolder()
|
||||
Screengrab.screenshot("ThreeDotMenuBookmarksRobot_edit-bookmark-folder-menu")
|
||||
// It may be needed to wait here to have the screenshot
|
||||
bookmarksMenu {
|
||||
navigateUp()
|
||||
}.openThreeDotMenu("test") {
|
||||
deleteBookmarkFolder()
|
||||
Screengrab.screenshot("ThreeDotMenuBookmarksRobot_delete-bookmark-folder-menu")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun collectionMenuTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
navigationToolbar {
|
||||
Screengrab.screenshot("NavigationToolbarRobot_navigation-toolbar")
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
Screengrab.screenshot("BrowserRobot_enter-url")
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
TestAssetHelper.waitingTime
|
||||
Screengrab.screenshot("TabDrawerRobot_one-tab-open")
|
||||
}.openThreeDotMenu {
|
||||
TestAssetHelper.waitingTime
|
||||
Screengrab.screenshot("TabDrawerRobot_three-dot-menu")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tabMenuTest() {
|
||||
val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(defaultWebPage.url) {
|
||||
}.openThreeDotMenu {
|
||||
Screengrab.screenshot("TabDrawerRobot_browser-tab-menu")
|
||||
}.closeBrowserMenuToBrowser {
|
||||
}.openComposeTabDrawer(composeTestRule) {
|
||||
Screengrab.screenshot("TabDrawerRobot_tab-drawer-with-tabs")
|
||||
closeTab()
|
||||
TestAssetHelper.waitingTime
|
||||
Screengrab.screenshot("TabDrawerRobot_remove-tab")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun saveLoginPromptTest() {
|
||||
val saveLoginTest =
|
||||
TestAssetHelper.getSaveLoginAsset(mockWebServer)
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(saveLoginTest.url) {
|
||||
verifySaveLoginPromptIsShownNotSave()
|
||||
SystemClock.sleep(TestAssetHelper.waitingTimeShort)
|
||||
Screengrab.screenshot("save-login-prompt")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
||||
|
||||
class ADBrun(object):
|
||||
binary = "adbrun"
|
||||
binary = 'adbrun'
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
def launch(self):
|
||||
# First close sim if any then launch
|
||||
os.system(
|
||||
"~/Library/Android/sdk/platform-tools/adb devices | grep emulator | cut -f1 | while read line; do ~/Library/Android/sdk/platform-tools/adb -s $line emu kill; done"
|
||||
)
|
||||
os.system('~/Library/Android/sdk/platform-tools/adb devices | grep emulator | cut -f1 | while read line; do ~/Library/Android/sdk/platform-tools/adb -s $line emu kill; done')
|
||||
# Then launch sim
|
||||
os.system("sh launchSimScript.sh")
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue