Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pushapkscript/docker.d/init_worker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ case $COT_PRODUCT in
export GOOGLE_CREDENTIALS_FOCUS_DEP_PATH=$CONFIG_DIR/fake_cert.json
export SGS_SERVICE_ACCOUNT_ID_DEP="0123456"
export SGS_ACCESS_TOKEN_DEP="dummy"
export HUAWEI_CLIENT_ID_DEP="0123456"
export HUAWEI_ACCESS_TOKEN_DEP="dummy"

import_cert fenix $CERT_DIR/fenix_dep.pem
import_cert focus $CERT_DIR/focus_dep.pem
Expand All @@ -85,6 +87,8 @@ case $COT_PRODUCT in
test_var_set 'GOOGLE_SERVICE_ACCOUNT_FENIX_RELEASE'
test_var_set 'SGS_SERVICE_ACCOUNT_ID'
test_var_set 'SGS_ACCESS_TOKEN'
test_var_set 'HUAWEI_CLIENT_ID'
test_var_set 'HUAWEI_ACCESS_TOKEN'

export GOOGLE_CREDENTIALS_FOCUS_PATH=$CONFIG_DIR/focus.json
export GOOGLE_CREDENTIALS_FENIX_NIGHTLY_PATH=$CONFIG_DIR/fenix_nightly.json
Expand Down
12 changes: 12 additions & 0 deletions pushapkscript/docker.d/worker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ products:
samsung:
service_account_id: { "$eval": "SGS_SERVICE_ACCOUNT_ID" }
access_token: { "$eval": "SGS_ACCESS_TOKEN" }
huawei:
client_id: { "$eval": "HUAWEI_CLIENT_ID" }
access_token: { "$eval": "HUAWEI_ACCESS_TOKEN" }
- product_names: ["focus-android" ]
digest_algorithm: 'SHA-256'
skip_check_ordered_version_codes: true
Expand Down Expand Up @@ -70,6 +73,9 @@ products:
samsung:
service_account_id: { "$eval": "SGS_SERVICE_ACCOUNT_ID" }
access_token: { "$eval": "SGS_ACCESS_TOKEN" }
huawei:
client_id: { "$eval": "HUAWEI_CLIENT_ID" }
access_token: { "$eval": "HUAWEI_ACCESS_TOKEN" }
klar-release:
package_names: ["org.mozilla.klar"]
certificate_alias: 'focus'
Expand Down Expand Up @@ -104,6 +110,9 @@ products:
samsung:
service_account_id: { "$eval": "SGS_SERVICE_ACCOUNT_ID_DEP" }
access_token: { "$eval": "SGS_ACCESS_TOKEN_DEP" }
huawei:
client_id: { "$eval": "HUAWEI_CLIENT_ID_DEP" }
access_token: { "$eval": "HUAWEI_ACCESS_TOKEN_DEP" }
- product_names: ["focus-android" ]
digest_algorithm: "SHA-256"
skip_check_ordered_version_codes: true
Expand Down Expand Up @@ -132,6 +141,9 @@ products:
samsung:
service_account_id: { "$eval": "SGS_SERVICE_ACCOUNT_ID_DEP" }
access_token: { "$eval": "SGS_ACCESS_TOKEN_DEP" }
huawei:
client_id: { "$eval": "HUAWEI_CLIENT_ID_DEP" }
access_token: { "$eval": "HUAWEI_ACCESS_TOKEN_DEP" }
klar-release:
package_names: ["org.mozilla.klar"]
certificate_alias: 'focus'
Expand Down
4 changes: 4 additions & 0 deletions pushapkscript/examples/config.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
"samsung": {
"sgs_service_account_id": "0123456",
"sgs_access_token": "abcdef"
},
"huawei": {
"client_id": "0123456",
"access_token": "abcdef"
}
}
}
Expand Down
1 change: 1 addition & 0 deletions pushapkscript/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
]
dependencies = [
# TODO: bump to >=12.0.0 once mozapkpublisher 12.0.0 (huawei store) is on PyPI

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: what was your experience between mozapkpublisher and pushapkscript? Did the split make it easier to test changes locally? If you were to implement a worker that publishes to Android stores, would you split these 2 packages?

I don't have any preferences in the answer, I just want to gauge if this split is still worth it today.

"mozapkpublisher",
"scriptworker",
]
Expand Down
16 changes: 16 additions & 0 deletions pushapkscript/src/pushapkscript/data/config_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,22 @@
"type": "string"
}
}
},
"huawei": {
"type": "object",
"required": [
"client_id",
"access_token"
],
"additionalProperties": false,
"properties": {
"client_id": {
"type": "string"
},
"access_token": {
"type": "string"
}
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion pushapkscript/src/pushapkscript/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ async def publish(product_config, publish_config, apk_files, contact_server):
skip_checks_fennec=bool(product_config.get("skip_checks_fennec")),
sgs_service_account_id=publish_config.get("sgs_service_account_id"),
sgs_access_token=publish_config.get("sgs_access_token"),
# Note that this only has an effect on SGS submissions, not google play.
huawei_client_id=publish_config.get("huawei_client_id"),
huawei_access_token=publish_config.get("huawei_access_token"),
# Note that this only has an effect on SGS and Huawei submissions, not google play.
submit=publish_config.get("submit", False),
)

Expand Down
21 changes: 17 additions & 4 deletions pushapkscript/src/pushapkscript/publish_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

log = logging.getLogger(__name__)

# Non-Google stores produce the same publish-config shape and differ only in which
# credential keys they expose. Maps target_store -> {output_key: store_config_key}.
_NON_GOOGLE_STORE_CREDENTIALS = {
"samsung": {
"sgs_service_account_id": "service_account_id",
"sgs_access_token": "access_token",
},
"huawei": {
"huawei_client_id": "client_id",
"huawei_access_token": "access_token",
},
}


def _should_do_dry_run(task):
# Don't commit anything by default. Committed APKs can't be unpublished,
Expand Down Expand Up @@ -70,18 +83,18 @@ def _get_channel_publish_config(product_config, task):
store_config = publish_config[target_store]
rollout_percentage = task.get("rollout_percentage")

if target_store == "samsung":
if target_store in _NON_GOOGLE_STORE_CREDENTIALS:
if task.get("google_play_track"):
raise ValueError("`google_play_track` is not allowed on the task if the target store is samsung")
raise ValueError(f"`google_play_track` is not allowed on the task if the target store is {target_store}")

credentials = {output_key: store_config[config_key] for output_key, config_key in _NON_GOOGLE_STORE_CREDENTIALS[target_store].items()}
return {
"target_store": target_store,
"dry_run": _should_do_dry_run(task),
"package_names": publish_config["package_names"],
"rollout_percentage": rollout_percentage,
"sgs_service_account_id": store_config["service_account_id"],
"sgs_access_token": store_config["access_token"],
"submit": task.get("submit", False),
**credentials,
}

google_track = task.get("google_play_track", store_config["default_track"])
Expand Down
51 changes: 51 additions & 0 deletions pushapkscript/tests/integration/test_integration_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ def generate_fenix_config(self):
"service_account_id": "123",
"access_token": "456",
},
"huawei": {
"client_id": "789",
"access_token": "abc",
},
},
},
}
Expand Down Expand Up @@ -238,6 +242,8 @@ def test_main_fennec_style(self, push_apk):
skip_checks_fennec=False,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

Expand Down Expand Up @@ -268,6 +274,8 @@ def test_main_focus_style(self, push_apk):
skip_checks_fennec=True,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

Expand Down Expand Up @@ -298,6 +306,8 @@ def test_main_fenix_style(self, push_apk):
skip_checks_fennec=True,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

Expand Down Expand Up @@ -328,6 +338,8 @@ def test_main_downloads_verifies_signature_and_gives_the_right_config_to_mozapkp
skip_checks_fennec=False,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

Expand Down Expand Up @@ -358,6 +370,8 @@ def test_main_allows_rollout_percentage(self, push_apk):
skip_checks_fennec=False,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

Expand Down Expand Up @@ -389,6 +403,8 @@ def test_main_allows_commit_transaction(self, push_apk):
skip_checks_fennec=False,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

Expand Down Expand Up @@ -420,5 +436,40 @@ def test_main_with_samsung_store(self, push_apk):
skip_checks_fennec=True,
sgs_service_account_id="123",
sgs_access_token="456",
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

@unittest.mock.patch("pushapkscript.publish.push_apk")
def test_main_with_huawei_store(self, push_apk):
task_generator = TaskGenerator(should_commit_transaction=True, store="huawei")

self.write_task_file(task_generator.generate_task("fenix", channel="release"))

self._copy_all_apks_to_test_temp_dir(task_generator)
self.keystore_manager.add_certificate("nightly")
main(config_path=self.config_generator.generate_fenix_config())

push_apk.assert_called_with(
apks=[
MockFile("{}/work/cot/{}/public/build/target.apk".format(self.test_temp_dir, task_generator.arm_task_id)),
MockFile("{}/work/cot/{}/public/build/target.apk".format(self.test_temp_dir, task_generator.x86_task_id)),
],
secret=None,
track=None,
expected_package_names=["org.mozilla.fenix"],
store="huawei",
rollout_percentage=None,
dry_run=False,
contact_server=True,
skip_check_multiple_locales=True,
skip_check_ordered_version_codes=False,
skip_check_same_locales=True,
skip_checks_fennec=True,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't block the merge: What are the reasons for skipping the Fennec checks? For reference, this is what they do:

https://github.com/mozilla-releng/mozapkpublisher/blob/1dd73f8157075719dca9dfe4116a533ad3680cb4/mozapkpublisher/common/apk/checker.py#L23-L31

This flag was introduced in mozilla-releng/mozapkpublisher#156 to support more products than Firefox itself. Firefox for Android has its quirks compare to simpler apps.

sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id="789",
huawei_access_token="abc",
submit=False,
)
4 changes: 4 additions & 0 deletions pushapkscript/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ def test_firefox_fake_prod():
"GOOGLE_CREDENTIALS_FOCUS_DEP_PATH": "focus",
"SGS_SERVICE_ACCOUNT_ID_DEP": "123456",
"SGS_ACCESS_TOKEN_DEP": "abcdef",
"HUAWEI_CLIENT_ID_DEP": "123456",
"HUAWEI_ACCESS_TOKEN_DEP": "abcdef",
}
_validate_config(context)

Expand All @@ -81,5 +83,7 @@ def test_firefox_prod():
"GOOGLE_CREDENTIALS_FOCUS_PATH": "focus",
"SGS_SERVICE_ACCOUNT_ID": "123456",
"SGS_ACCESS_TOKEN": "abcdef",
"HUAWEI_CLIENT_ID": "123456",
"HUAWEI_ACCESS_TOKEN": "abcdef",
}
_validate_config(context)
3 changes: 3 additions & 0 deletions pushapkscript/tests/test_publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ async def test_publish_config(self, mock_push_aab, mock_push_apk):
skip_checks_fennec=False,
sgs_service_account_id=None,
sgs_access_token=None,
huawei_client_id=None,
huawei_access_token=None,
submit=False,
)

async def test_publish_aab_config(self, mock_push_aab, mock_push_apk):
Expand Down
66 changes: 66 additions & 0 deletions pushapkscript/tests/test_publish_config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pytest

from pushapkscript.publish_config import _should_do_dry_run, get_publish_config

AURORA_CONFIG = {
Expand Down Expand Up @@ -28,6 +30,7 @@
"certificate_alias": "fenix",
"google": {"default_track": "internal", "credentials_file": "fenix.json"},
"samsung": {"service_account_id": "123456", "access_token": "abcdef"},
"huawei": {"client_id": "654321", "access_token": "fedcba"},
}
}
}
Expand Down Expand Up @@ -200,6 +203,69 @@ def test_target_samsung_submit():
}


def test_target_huawei():
payload = {"channel": "production", "target_store": "huawei"}

assert get_publish_config(FENIX_CONFIG, payload, "fenix") == {
"target_store": "huawei",
"dry_run": True,
"huawei_client_id": "654321",
"huawei_access_token": "fedcba",
"package_names": ["org.mozilla.fenix"],
"rollout_percentage": None,
"submit": False,
}


def test_target_huawei_with_commit():
payload = {"channel": "production", "target_store": "huawei", "commit": True}

assert get_publish_config(FENIX_CONFIG, payload, "fenix") == {
"target_store": "huawei",
"dry_run": False,
"huawei_client_id": "654321",
"huawei_access_token": "fedcba",
"package_names": ["org.mozilla.fenix"],
"rollout_percentage": None,
"submit": False,
}


def test_target_huawei_rollout():
payload = {"channel": "production", "target_store": "huawei", "rollout_percentage": 50}

assert get_publish_config(FENIX_CONFIG, payload, "fenix") == {
"target_store": "huawei",
"dry_run": True,
"huawei_client_id": "654321",
"huawei_access_token": "fedcba",
"package_names": ["org.mozilla.fenix"],
"rollout_percentage": 50,
"submit": False,
}


def test_target_huawei_submit():
payload = {"channel": "production", "target_store": "huawei", "submit": True}

assert get_publish_config(FENIX_CONFIG, payload, "fenix") == {
"target_store": "huawei",
"dry_run": True,
"huawei_client_id": "654321",
"huawei_access_token": "fedcba",
"package_names": ["org.mozilla.fenix"],
"rollout_percentage": None,
"submit": True,
}


def test_target_huawei_rejects_google_play_track():
payload = {"channel": "production", "target_store": "huawei", "google_play_track": "production"}

with pytest.raises(ValueError, match="`google_play_track` is not allowed"):
get_publish_config(FENIX_CONFIG, payload, "fenix")


def test_should_do_dry_run():
task_payload = {"commit": True}
assert _should_do_dry_run(task_payload) is False
Expand Down