Compare commits
No commits in common. 'fork' and 'iceraven-2.10.0' have entirely different histories.
fork
...
iceraven-2
@ -0,0 +1,152 @@
|
||||
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-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-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
|
@ -1,41 +0,0 @@
|
||||
# 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}
|
@ -1,108 +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.
|
||||
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."
|
@ -1,5 +0,0 @@
|
||||
# .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
|
@ -1,31 +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/.
|
||||
|
||||
# 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
|
@ -1,91 +0,0 @@
|
||||
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
|
@ -1,19 +0,0 @@
|
||||
---
|
||||
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: ?
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
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: ?
|
@ -1,24 +0,0 @@
|
||||
---
|
||||
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.
|
||||
|
@ -1,21 +0,0 @@
|
||||
---
|
||||
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
|
@ -1,13 +0,0 @@
|
||||
---
|
||||
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:
|
@ -1,13 +0,0 @@
|
||||
---
|
||||
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:
|
@ -1,14 +0,0 @@
|
||||
|
||||
|
||||
### 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.
|
@ -1,115 +0,0 @@
|
||||
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
|
@ -1,143 +0,0 @@
|
||||
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
|
@ -1,24 +0,0 @@
|
||||
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.
Before Width: | Height: | Size: 99 KiB |
@ -1,63 +0,0 @@
|
||||
# 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 🌟"
|
@ -0,0 +1,86 @@
|
||||
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
|
||||
|
||||
- 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
|
@ -1,16 +0,0 @@
|
||||
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"
|
@ -0,0 +1,3 @@
|
||||
[submodule "android-components"]
|
||||
path = android-components
|
||||
url = https://github.com/akliuxingyuan/android-components
|
@ -1,122 +0,0 @@
|
||||
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
|
@ -1,293 +0,0 @@
|
||||
---
|
||||
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}'
|
@ -1,16 +0,0 @@
|
||||
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)"
|
||||
|
@ -1,373 +0,0 @@
|
||||
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.
|
@ -0,0 +1 @@
|
||||
Subproject commit af760b7d977c0390af7b844a657ff6b56056abf1
|
@ -0,0 +1,228 @@
|
||||
---
|
||||
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."
|
||||
glean:
|
||||
description: A feature that provides server-side configurations for Glean metrics (aka Server Knobs).
|
||||
hasExposure: true
|
||||
exposureDescription: ""
|
||||
variables:
|
||||
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.
|
||||
enabled:
|
||||
type: boolean
|
||||
description: "if true, juno onboarding is shown to the user."
|
||||
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."
|
||||
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
@ -0,0 +1,448 @@
|
||||
---
|
||||
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
|
||||
}
|
||||
defaults:
|
||||
- channel: developer
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"feature-ui": 1,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4
|
||||
}
|
||||
}
|
||||
- channel: nightly
|
||||
value: {
|
||||
"sections-enabled": {
|
||||
"feature-ui": 1,
|
||||
"feature-setting-value": 0,
|
||||
"dialog-re-engage-time": 4
|
||||
}
|
||||
}
|
||||
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: false
|
||||
|
||||
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: {}
|
||||
|
||||
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
|
||||
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: {}
|
||||
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.
|
||||
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.
|
@ -0,0 +1,126 @@
|
||||
---
|
||||
features:
|
||||
|
||||
juno-onboarding:
|
||||
description: A feature that shows juno onboarding flow.
|
||||
|
||||
variables:
|
||||
enabled:
|
||||
description: if true, juno onboarding is shown to the user.
|
||||
type: Boolean
|
||||
default: false
|
||||
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
|
||||
ordering: 10
|
||||
body: juno_onboarding_default_browser_description_nimbus
|
||||
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
|
||||
body: juno_onboarding_sign_in_description
|
||||
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
|
||||
body: juno_onboarding_enable_notifications_description_nimbus
|
||||
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
|
||||
|
||||
defaults:
|
||||
- channel: developer
|
||||
value:
|
||||
enabled: false
|
||||
- channel: nightly
|
||||
value:
|
||||
enabled: true
|
||||
|
||||
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.
|
@ -0,0 +1,19 @@
|
||||
---
|
||||
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: true
|
||||
- channel: nightly
|
||||
value:
|
||||
felt-privacy-enabled: false
|
@ -0,0 +1,49 @@
|
||||
<!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,14 +1,49 @@
|
||||
<!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 id="video-container">
|
||||
<video id="videoSample" width="320" height="240" controls loop>
|
||||
<source src="../resources/clip.mp4">
|
||||
<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.
|
||||
</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.
@ -0,0 +1,17 @@
|
||||
[[source]]
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pytest = "*"
|
||||
pytest-html = "*"
|
||||
pytest-metadata = "*"
|
||||
requests = "*"
|
||||
|
||||
[dev-packages]
|
||||
black = "*"
|
||||
flake8 = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.11"
|
@ -0,0 +1,285 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "917d5c85bd6545dedfbce6aedbd76bd1516993e65943ecfbf7affbece9a2a0ab"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.11"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"black": {
|
||||
"hashes": [
|
||||
"sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5",
|
||||
"sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915",
|
||||
"sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326",
|
||||
"sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940",
|
||||
"sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b",
|
||||
"sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30",
|
||||
"sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c",
|
||||
"sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c",
|
||||
"sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab",
|
||||
"sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27",
|
||||
"sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2",
|
||||
"sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961",
|
||||
"sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9",
|
||||
"sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb",
|
||||
"sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70",
|
||||
"sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331",
|
||||
"sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2",
|
||||
"sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266",
|
||||
"sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d",
|
||||
"sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6",
|
||||
"sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b",
|
||||
"sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925",
|
||||
"sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8",
|
||||
"sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4",
|
||||
"sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==23.3.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7",
|
||||
"sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2023.5.7"
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6",
|
||||
"sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1",
|
||||
"sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e",
|
||||
"sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373",
|
||||
"sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62",
|
||||
"sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230",
|
||||
"sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be",
|
||||
"sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c",
|
||||
"sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0",
|
||||
"sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448",
|
||||
"sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f",
|
||||
"sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649",
|
||||
"sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d",
|
||||
"sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0",
|
||||
"sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706",
|
||||
"sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a",
|
||||
"sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59",
|
||||
"sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23",
|
||||
"sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5",
|
||||
"sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb",
|
||||
"sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e",
|
||||
"sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e",
|
||||
"sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c",
|
||||
"sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28",
|
||||
"sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d",
|
||||
"sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41",
|
||||
"sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974",
|
||||
"sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce",
|
||||
"sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f",
|
||||
"sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1",
|
||||
"sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d",
|
||||
"sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8",
|
||||
"sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017",
|
||||
"sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31",
|
||||
"sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7",
|
||||
"sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8",
|
||||
"sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e",
|
||||
"sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14",
|
||||
"sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd",
|
||||
"sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d",
|
||||
"sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795",
|
||||
"sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b",
|
||||
"sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b",
|
||||
"sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b",
|
||||
"sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203",
|
||||
"sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f",
|
||||
"sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19",
|
||||
"sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1",
|
||||
"sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a",
|
||||
"sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac",
|
||||
"sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9",
|
||||
"sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0",
|
||||
"sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137",
|
||||
"sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f",
|
||||
"sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6",
|
||||
"sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5",
|
||||
"sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909",
|
||||
"sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f",
|
||||
"sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0",
|
||||
"sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324",
|
||||
"sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755",
|
||||
"sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb",
|
||||
"sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854",
|
||||
"sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c",
|
||||
"sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60",
|
||||
"sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84",
|
||||
"sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0",
|
||||
"sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b",
|
||||
"sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1",
|
||||
"sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531",
|
||||
"sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1",
|
||||
"sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11",
|
||||
"sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326",
|
||||
"sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df",
|
||||
"sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"
|
||||
],
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
|
||||
"sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==8.1.3"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7",
|
||||
"sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.0.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"
|
||||
},
|
||||
"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:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
|
||||
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==23.1"
|
||||
},
|
||||
"pathspec": {
|
||||
"hashes": [
|
||||
"sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687",
|
||||
"sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.11.1"
|
||||
},
|
||||
"platformdirs": {
|
||||
"hashes": [
|
||||
"sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc",
|
||||
"sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.8.0"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849",
|
||||
"sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719",
|
||||
"sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053",
|
||||
"sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.10.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf",
|
||||
"sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32",
|
||||
"sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==7.4.0"
|
||||
},
|
||||
"pytest-html": {
|
||||
"hashes": [
|
||||
"sha256:868c08564a68d8b2c26866f1e33178419bb35b1e127c33784a28622eb827f3f3",
|
||||
"sha256:c4e2f4bb0bffc437f51ad2174a8a3e71df81bbc2f6894604e604af18fbe687c3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"pytest-metadata": {
|
||||
"hashes": [
|
||||
"sha256:769a9c65d2884bd583bc626b0ace77ad15dbe02dd91a9106d47fd46d9c2569ca",
|
||||
"sha256:a17b1e40080401dc23177599208c52228df463db191c1a573ccdffacd885e190"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
|
||||
"sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.31.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1",
|
||||
"sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.0.3"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/* 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.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()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
TestHelper.appContext.settings().showSecretDebugMenuThisSession = true
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
TestHelper.appContext.settings().showSecretDebugMenuThisSession = false
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkSurveyNavigatesCorrectly() {
|
||||
browserScreen {
|
||||
verifySurveyButton()
|
||||
}.clickSurveyButton {}
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openExperimentsMenu {
|
||||
verifyExperimentExists(experimentName)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
import json
|
||||
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 load_branches():
|
||||
branches = []
|
||||
data = requests.get(f"{KLAATU_SERVER_URL}/experiment").json()
|
||||
for item in reversed(data):
|
||||
if isinstance(item, dict):
|
||||
exit()
|
||||
else:
|
||||
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()
|
||||
del(data["branches"][0]["features"][0]["value"]["message-under-experiment"])
|
||||
for item in data["branches"][0]["features"][0]["value"]["messages"].values():
|
||||
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():
|
||||
data = requests.get(f"{KLAATU_LOCAL_SERVER_URL}/experiment").json()
|
||||
url = None
|
||||
for item in data:
|
||||
if isinstance(item, dict):
|
||||
continue
|
||||
else:
|
||||
url = item
|
||||
yield url
|
||||
return_data = {"url": url}
|
||||
requests.put(f"{KLAATU_SERVER_URL}/experiment", json=return_data)
|
||||
|
||||
|
||||
@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}
|
||||
requests.post(f"{KLAATU_SERVER_URL}/test_results", files=files)
|
||||
|
||||
|
||||
@pytest.fixture(name="setup_experiment", params=load_branches(), autouse=True)
|
||||
def fixture_setup_experiment(experiment_slug, json_data, gradlewbuild_log, request):
|
||||
def _():
|
||||
command = f"nimbus-cli --app fenix --channel developer enroll {experiment_slug} --branch {request.param} --file {json_data} --reset-app"
|
||||
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 _
|
@ -0,0 +1,45 @@
|
||||
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))
|
@ -0,0 +1,26 @@
|
||||
#!/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
|
@ -0,0 +1,4 @@
|
||||
[pytest]
|
||||
addopts = --verbose --html=results/index.html --self-contained-html
|
||||
log_cli = true
|
||||
log_cli_level = info
|
@ -0,0 +1,3 @@
|
||||
def test_survey_navigates_correctly(setup_experiment, gradlewbuild):
|
||||
setup_experiment()
|
||||
gradlewbuild.test("SurveyExperimentIntegrationTest#checkSurveyNavigatesCorrectly")
|
@ -0,0 +1,62 @@
|
||||
/* 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_controlled_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_must_be_disabled_by_default() {
|
||||
val runtime = GeckoProvider.createRuntimeSettings(context, policy)
|
||||
|
||||
assertFalse(FxNimbus.features.extensionsProcess.value().enabled)
|
||||
assertFalse(runtime.extensionsProcessEnabled!!)
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/* 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
/* 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,
|
||||
)
|
@ -0,0 +1,189 @@
|
||||
/* 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,16 +1,17 @@
|
||||
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")
|
||||
|
@ -0,0 +1,117 @@
|
||||
/* 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.ui
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemContainingText
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper
|
||||
import org.mozilla.fenix.ui.robots.browserScreen
|
||||
import org.mozilla.fenix.ui.robots.clickPageObject
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
import org.mozilla.fenix.ui.robots.searchScreen
|
||||
|
||||
class AddToHomeScreenTest {
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
private val downloadTestPage =
|
||||
"https://storage.googleapis.com/mobile_test_assets/test_app/downloads.html"
|
||||
private val pdfFileName = "washington.pdf"
|
||||
private val pdfFileURL = "storage.googleapis.com/mobile_test_assets/public/washington.pdf"
|
||||
private val pdfFileContent = "Washington Crossing the Delaware"
|
||||
|
||||
@get:Rule
|
||||
val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
// Verifies the Add to home screen option in a tab's 3 dot menu
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun mainMenuAddToHomeScreenTest() {
|
||||
val website = TestAssetHelper.getGenericAsset(mockWebServer, 1)
|
||||
val shortcutTitle = TestHelper.generateRandomString(5)
|
||||
|
||||
homeScreen {
|
||||
}.openNavigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(website.url) {
|
||||
}.openThreeDotMenu {
|
||||
expandMenu()
|
||||
}.openAddToHomeScreen {
|
||||
clickCancelShortcutButton()
|
||||
}
|
||||
|
||||
browserScreen {
|
||||
}.openThreeDotMenu {
|
||||
expandMenu()
|
||||
}.openAddToHomeScreen {
|
||||
verifyShortcutTextFieldTitle("Test_Page_1")
|
||||
addShortcutName(shortcutTitle)
|
||||
clickAddShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut(shortcutTitle) {
|
||||
verifyUrl(website.url.toString())
|
||||
verifyTabCounter("1")
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun addPrivateBrowsingShortcutTest() {
|
||||
homeScreen {
|
||||
}.dismissOnboarding()
|
||||
|
||||
homeScreen {
|
||||
}.triggerPrivateBrowsingShortcutPrompt {
|
||||
verifyNoThanksPrivateBrowsingShortcutButton()
|
||||
verifyAddPrivateBrowsingShortcutButton()
|
||||
clickAddPrivateBrowsingShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut("Private ${TestHelper.appName}") {}
|
||||
searchScreen {
|
||||
verifySearchView()
|
||||
}.dismissSearchBar {
|
||||
verifyCommonMythsLink()
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun addPDFToHomeScreenTest() {
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(downloadTestPage.toUri()) {
|
||||
clickPageObject(itemContainingText(pdfFileName))
|
||||
verifyUrl(pdfFileURL)
|
||||
verifyPageContent(pdfFileContent)
|
||||
}.openThreeDotMenu {
|
||||
expandMenu()
|
||||
}.openAddToHomeScreen {
|
||||
verifyShortcutTextFieldTitle(pdfFileName)
|
||||
clickAddShortcutButton()
|
||||
clickAddAutomaticallyButton()
|
||||
}.openHomeScreenShortcut(pdfFileName) {
|
||||
verifyUrl(pdfFileURL)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,436 @@
|
||||
/* 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.ui
|
||||
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.customannotations.SmokeTest
|
||||
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
|
||||
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemWithResId
|
||||
import org.mozilla.fenix.helpers.MatcherHelper.itemWithResIdContainingText
|
||||
import org.mozilla.fenix.helpers.TestAssetHelper
|
||||
import org.mozilla.fenix.helpers.TestHelper.exitMenu
|
||||
import org.mozilla.fenix.helpers.TestHelper.packageName
|
||||
import org.mozilla.fenix.ui.robots.clickPageObject
|
||||
import org.mozilla.fenix.ui.robots.homeScreen
|
||||
import org.mozilla.fenix.ui.robots.navigationToolbar
|
||||
|
||||
class AddressAutofillTest {
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
|
||||
@get:Rule
|
||||
val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer().apply {
|
||||
dispatcher = AndroidAssetDispatcher()
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun verifyAddressAutofillTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}.goBack {
|
||||
}.goBack {
|
||||
}
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Harrison Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Harrison Street")
|
||||
}
|
||||
}
|
||||
|
||||
@SmokeTest
|
||||
@Test
|
||||
fun deleteSavedAddressTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickSavedAddress("Mozilla")
|
||||
clickDeleteAddressButton()
|
||||
clickCancelDeleteAddressButton()
|
||||
clickDeleteAddressButton()
|
||||
clickConfirmDeleteAddressButton()
|
||||
verifyAddAddressButton()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyAddAddressViewTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
verifyAddAddressView()
|
||||
}.goBackToAutofillSettings {
|
||||
verifyAutofillToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyEditAddressViewTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickSavedAddress("Mozilla")
|
||||
verifyEditAddressView()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyAddressAutofillToggleTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
verifySelectAddressButtonExists(true)
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickSaveAndAutofillAddressesOption()
|
||||
verifyAddressAutofillSection(false, true)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
verifySelectAddressButtonExists(false)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyManageAddressesPromptOptionTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
}.clickManageAddressButton {
|
||||
verifyAutofillToolbarTitle()
|
||||
}.goBackToBrowser {
|
||||
verifySaveLoginPromptIsNotDisplayed()
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Failing, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1814032")
|
||||
@Test
|
||||
fun verifyAddressAutofillSelectionTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Android",
|
||||
"Test",
|
||||
"Name",
|
||||
"Fort Street",
|
||||
"San Jose",
|
||||
"Arizona",
|
||||
"95141",
|
||||
"United States",
|
||||
"777-7777",
|
||||
"fuu@bar.org",
|
||||
)
|
||||
verifyManageAddressesToolbarTitle()
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Harrison Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Harrison Street")
|
||||
clearAddressForm()
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Fort Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Fort Street")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifySavedAddressCanBeEditedTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
clickManageAddressesButton()
|
||||
clickSavedAddress("Mozilla")
|
||||
fillAndSaveAddress(
|
||||
"Android",
|
||||
"Test",
|
||||
"Name",
|
||||
"Fort Street",
|
||||
"San Jose",
|
||||
"Arizona",
|
||||
"95141",
|
||||
"United States",
|
||||
"777-7777",
|
||||
"fuu@bar.org",
|
||||
)
|
||||
verifyManageAddressesToolbarTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyStateFieldUpdatesInAccordanceWithCountryFieldTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
verifyCountryOption("United States")
|
||||
verifyStateOption("Alabama")
|
||||
verifyCountryOptions("Canada", "United States")
|
||||
clickCountryOption("Canada")
|
||||
verifyStateOption("Alberta")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyFormFieldCanBeFilledManuallyTest() {
|
||||
val addressFormPage =
|
||||
TestAssetHelper.getAddressFormAsset(mockWebServer)
|
||||
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
|
||||
exitMenu()
|
||||
|
||||
navigationToolbar {
|
||||
}.enterURLAndEnterToBrowser(addressFormPage.url) {
|
||||
clickPageObject(itemWithResId("streetAddress"))
|
||||
clickSelectAddressButton()
|
||||
clickPageObject(
|
||||
itemWithResIdContainingText(
|
||||
"$packageName:id/address_name",
|
||||
"Harrison Street",
|
||||
),
|
||||
)
|
||||
verifyAutofilledAddress("Harrison Street")
|
||||
setTextForApartmentTextBox("Ap. 07")
|
||||
verifyManuallyFilledAddress("Ap. 07")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyAutofillAddressSectionTest() {
|
||||
homeScreen {
|
||||
}.openThreeDotMenu {
|
||||
}.openSettings {
|
||||
}.openAutofillSubMenu {
|
||||
verifyAddressAutofillSection(true, false)
|
||||
clickAddAddressButton()
|
||||
fillAndSaveAddress(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"United States",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
verifyAddressAutofillSection(true, true)
|
||||
clickManageAddressesButton()
|
||||
verifyManageAddressesSection(
|
||||
"Mozilla",
|
||||
"Fenix",
|
||||
"Firefox",
|
||||
"Harrison Street",
|
||||
"San Francisco",
|
||||
"Alaska",
|
||||
"94105",
|
||||
"US",
|
||||
"555-5555",
|
||||
"foo@bar.com",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue