Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/MetaMask/metamask-mobile in…
Browse files Browse the repository at this point in the history
…to morph/checkbox-update
  • Loading branch information
brianacnguyen committed Aug 2, 2023
2 parents 0497ff5 + 68c642c commit b46e7c9
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 52 deletions.
1 change: 1 addition & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ When you're done with your project / bugfix / feature and ready to submit a PR,
- [ ] **Keep it simple**: Try not to include multiple features in a single PR, and don't make extraneous changes outside the scope of your contribution. All those touched files make things harder to review ;)
- [ ] **PR against `main`**: Submit your PR against the `main` branch. This is where we merge new features to be included in forthcoming releases. When we initiate a new release, we create a branch named `release/x.y.z`, serving as a snapshot of the `main` branch. This particular branch is utilized to construct the builds, which are then tested during the release regression testing phase before they are submitted to the stores for production. In the event your PR is a hot-fix for a bug identified on the `release/x.y.z` branch, you should still submit your PR against the `main` branch. This PR will subsequently be cherry-picked into the `release/x.y.z` branch by our release engineers.
- [ ] **Get the PR reviewed by code owners**: At least two code owner approvals are mandatory before merging any PR.
- [ ] **Ensure the PR is correctly labeled.**: More detail about labels definitions can be found [here](https://github.com/MetaMask/metamask-mobile/blob/main/.github/coding_guidelines/LABELING_GUIDELINES.md).

And that's it! Thanks for helping out.
24 changes: 24 additions & 0 deletions .github/coding_guidelines/LABELING_GUIDELINES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# PR Labeling Guidelines
To maintain a consistent and efficient development workflow, we have set specific label guidelines for all pull requests (PRs). Please ensure you adhere to the following instructions:

### Mandatory Labels:
- **Internal Developers**: Every PR raised by an internal developer must include a label prefixed with `team-` (e.g., `team-mobile-ux`, `team-mobile-platform`, etc.). This indicates the respective internal team responsible for the PR.

- **External Contributors**: PRs from contributors outside the organization must have the `external-contributor` label.

It's essential to ensure that PRs have the appropriate labels before they are considered for merging.

### Prohibited Labels:
Any PR that includes one of the following labels can not be merged:

- **needs-qa**: The PR requires a full manual QA prior to being added to a release.
- **QA'd but questions**: The PR has been checked by QA, but there are pending questions or clarifications needed on minor issues that were found.
- **issues-found**: The PR has been checked by QA or other reviewers, and appeared to include issues that need to be addressed.
- **need-ux-ds-review**: The PR requires a review from the User Experience or Design System teams.
- **blocked**: There are unresolved dependencies or other issues blocking the progress of this PR.
- **stale**: The PR has not had recent activity in the last 90 days. It will be closed in 7 days.
- **DO-NOT-MERGE**: The PR should not be merged under any circumstances.

To maintain code quality and project integrity, it's crucial to respect these label guidelines. Please ensure you review and update labels appropriately throughout the PR lifecycle.

Thank you for your cooperation!
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Please ensure that any applicable requirements below are satisfied before submit
- `No QA/E2E only`: PR does not require any manual QA effort. Prior to merging, ensure that you have successful end-to-end test runs in Bitrise.
- `Spot check on release build`: PR does not require feature QA but needs non-automated verification. In the description section, provide test scenarios. Add screenshots, and or recordings of what was tested.
5. Add `QA Passed` label when QA has signed off (Only required if the PR was labeled with `needs-qa`)
6. Add your team's label, i.e. label starting with `team-` (or `external-contributor` label if your not a MetaMask employee)

**Description**

Expand Down
97 changes: 97 additions & 0 deletions .github/scripts/check-pr-has-required-labels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import * as core from '@actions/core';
import { context, getOctokit } from '@actions/github';
import { GitHub } from '@actions/github/lib/utils';

main().catch((error: Error): void => {
console.error(error);
process.exit(1);
});

async function main(): Promise<void> {
// "GITHUB_TOKEN" is an automatically generated, repository-specific access token provided by GitHub Actions.
const githubToken = process.env.GITHUB_TOKEN;
if (!githubToken) {
core.setFailed('GITHUB_TOKEN not found');
process.exit(1);
}

// Initialise octokit, required to call Github GraphQL API
const octokit: InstanceType<typeof GitHub> = getOctokit(githubToken);

// Retrieve pull request info from context
const prRepoOwner = context.repo.owner;
const prRepoName = context.repo.repo;
const prNumber = context.payload.pull_request?.number;
if (!prNumber) {
core.setFailed('Pull request number not found');
process.exit(1);
}

// Retrieve pull request labels
const prLabels = await retrievePullRequestLabels(octokit, prRepoOwner, prRepoName, prNumber);

const preventMergeLabels = ["needs-qa", "QA'd but questions", "issues-found", "need-ux-ds-review", "blocked", "stale", "DO-NOT-MERGE"];

let hasTeamLabel = false;

// Check pull request has at least required QA label and team label
for (const label of prLabels) {
if (label.startsWith("team-") || label === "external-contributor") {
console.log(`PR contains a team label as expected: ${label}`);
hasTeamLabel = true;
}
if (preventMergeLabels.includes(label)) {
throw new Error(`PR cannot be merged because it still contains this label: ${label}`);
}
if (hasTeamLabel) {
return;
}
}

// Otherwise, throw an arror to prevent from merging
let errorMessage = '';
if (!hasTeamLabel) {
errorMessage += 'No team labels found on the PR. ';
}
errorMessage += `Please make sure the PR is appropriately labeled before merging it.\n\nSee labeling guidelines for more detail: https://github.com/MetaMask/metamask-mobile/blob/main/.github/coding_guidelines/LABELING_GUIDELINES.md`;
throw new Error(errorMessage);

}

// This function retrieves the pull request on a specific repo
async function retrievePullRequestLabels(octokit: InstanceType<typeof GitHub>, repoOwner: string, repoName: string, prNumber: number): Promise<string[]> {

const retrievePullRequestLabelsQuery = `
query RetrievePullRequestLabels($repoOwner: String!, $repoName: String!, $prNumber: Int!) {
repository(owner: $repoOwner, name: $repoName) {
pullRequest(number: $prNumber) {
labels(first: 100) {
nodes {
name
}
}
}
}
}
`;

const retrievePullRequestLabelsResult: {
repository: {
pullRequest: {
labels: {
nodes: {
name: string;
}[];
}
};
};
} = await octokit.graphql(retrievePullRequestLabelsQuery, {
repoOwner,
repoName,
prNumber,
});

const pullRequestLabels = retrievePullRequestLabelsResult?.repository?.pullRequest?.labels?.nodes?.map(labelObject => labelObject?.name);

return pullRequestLabels || [];
}
38 changes: 38 additions & 0 deletions .github/workflows/check-pr-labels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: "Check PR has required labels"
on:
pull_request:
branches:
- main
types:
- opened
- reopened
- synchronize
- labeled
- unlabeled

jobs:
check-pr-labels:
runs-on: ubuntu-latest
permissions:
pull-requests: read

steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0 # This is needed to checkout all branches

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
cache: yarn

- name: Install dependencies
run: yarn --immutable

- name: Check PR has required labels
id: check-pr-has-required-labels
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run check-pr-has-required-labels
17 changes: 0 additions & 17 deletions .github/workflows/ci-all-branches.yml

This file was deleted.

7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,22 @@ sudo gem install cocoapods -v 1.12.1
- Locate `NDK (Side-by-side)` option in the tools list
- Check NDK version `21.4.7075529`
- Locate `CMake` option in the tools list
- Check CMake version `3.10.2`
- Check CMake version `3.22.1`
- Click "Apply" or "OK" to download
- Linux only:
- Ensure that you have the `secret-tool` binary on your machine.
- Part of the [libsecret-tools](https://launchpad.net/ubuntu/bionic/+package/libsecret-tools) package on Debian/Ubuntu based distributions.
- Install the correct emulator
- Follow the instructions at:
- [React Native Getting Started - Android](https://reactnative.dev/docs/environment-setup#installing-dependencies) _(React Native CLI Quickstart -> [your OS] -> Android)_
- FYI: as of today (7/18/23) there is currently an issue when running detox on android 12 and 13 (API 32/33) which prevents the tests from running. The issue is, the tap() action is treated like a tapAndHold() action. See the open issue in wix/detox [here](https://github.com/wix/Detox/issues/3762)
- More details can be found [on the Android Developer site](https://developer.android.com/studio/run/emulator)
- You should use the following:
- **Android OS Version:** Latest, unless told otherwise
- **Device:** Google Pixel 3
- **Device:** Google Pixel 5
- Finally, start the emulator from Android Studio:
- Open "Virtual Device Manager"
- Launch emulator for "Pixel 3 <relevant API version mentioned in [React Native Getting Started](https://reactnative.dev/docs/environment-setup#installing-dependencies)>"
- Launch emulator for "Pixel 5 <relevant API version mentioned in [React Native Getting Started](https://reactnative.dev/docs/environment-setup#installing-dependencies)>"


#### iOS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const styleSheet = (params: {
const { style, anchorElementShape, badgePosition, containerSize } = vars;
let anchoringOffset, positionObj, xOffset, yOffset;
const elementHeight = containerSize?.height || 0;
let isCustomPosition = false;

switch (anchorElementShape) {
case BadgeAnchorElementShape.Circular:
Expand Down Expand Up @@ -75,6 +76,7 @@ const styleSheet = (params: {
break;
default:
positionObj = badgePosition;
isCustomPosition = true;
xOffset = 0;
yOffset = 0;
}
Expand All @@ -84,16 +86,21 @@ const styleSheet = (params: {
{ position: 'relative', alignSelf: 'flex-start' } as ViewStyle,
style,
) as ViewStyle,
badge: {
// This is needed to pass the anchor element's bounding box to the Badge.
position: 'absolute',
height: elementHeight,
aspectRatio: 1,
alignItems: 'center',
justifyContent: 'center',
...positionObj,
transform: [{ translateX: xOffset }, { translateY: yOffset }],
},
badge: isCustomPosition
? {
position: 'absolute',
...positionObj,
}
: {
// This is needed to pass the anchor element's bounding box to the Badge.
position: 'absolute',
height: elementHeight,
aspectRatio: 1,
alignItems: 'center',
justifyContent: 'center',
...positionObj,
transform: [{ translateX: xOffset }, { translateY: yOffset }],
},
});
};

Expand Down
1 change: 0 additions & 1 deletion app/components/UI/SignatureRequest/Root/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const Root = ({
backdropOpacity={1}
animationInTiming={600}
animationOutTiming={600}
onBackdropPress={onSignReject}
onBackButtonPress={
showExpandedMessage ? toggleExpandedMessage : onSignReject
}
Expand Down
5 changes: 5 additions & 0 deletions e2e/pages/TabBarComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
TAB_BAR_BROWSER_BUTTON,
TAB_BAR_SETTING_BUTTON,
TAB_BAR_WALLET_BUTTON,
TAB_BAR_ACTIVITY_BUTTON,
} from '../../wdio/screen-objects/testIDs/Components/TabBar.testIds';

export default class TabBarComponent {
Expand All @@ -25,4 +26,8 @@ export default class TabBarComponent {
static async tapSettings() {
await TestHelpers.waitAndTap(TAB_BAR_SETTING_BUTTON);
}

static async tapActivity() {
await TestHelpers.waitAndTap(TAB_BAR_ACTIVITY_BUTTON);
}
}
60 changes: 60 additions & 0 deletions e2e/specs/confirmations/send-eth-multisig.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use strict';

import { Regression } from '../../tags';
import TestHelpers from '../../helpers';

import AmountView from '../../pages/AmountView';
import SendView from '../../pages/SendView';
import TransactionConfirmationView from '../../pages/TransactionConfirmView';
import {
importWalletWithRecoveryPhrase,
addLocalhostNetwork,
} from '../../viewHelper';
import TabBarComponent from '../../pages/TabBarComponent';
import WalletActionsModal from '../../pages/modals/WalletActionsModal';
import Accounts from '../../../wdio/helpers/Accounts';
import Ganache from '../../../app/util/test/ganache';
import root from '../../../locales/languages/en.json';

const validAccount = Accounts.getValidAccount();
const MULTISIG_ADDRESS = '0x0C1DD822d1Ddf78b0b702df7BF9fD0991D6255A1';
const AMOUNT_TO_SEND = '0.12345';
const TOKEN_NAME = root.unit.eth;

describe(Regression('Send tests'), () => {
let ganacheServer;
beforeAll(async () => {
jest.setTimeout(2500000);
if (device.getPlatform() === 'android') {
await device.reverseTcpPort('8081'); // because on android we need to expose the localhost ports to run ganache
await device.reverseTcpPort('8545');
}
ganacheServer = new Ganache();
await ganacheServer.start({ mnemonic: validAccount.seedPhrase });
});

afterAll(async () => {
await ganacheServer.quit();
});

it('Send ETH to a Multisig address from inside MetaMask wallet', async () => {
await importWalletWithRecoveryPhrase();
await addLocalhostNetwork();

await TabBarComponent.tapActions();
await WalletActionsModal.tapSendButton();

await SendView.inputAddress(MULTISIG_ADDRESS);
await SendView.tapNextButton();

await AmountView.typeInTransactionAmount(AMOUNT_TO_SEND);
await AmountView.tapNextButton();

await TransactionConfirmationView.tapConfirmButton();
await TabBarComponent.tapActivity();

await TestHelpers.checkIfElementByTextIsVisible(
AMOUNT_TO_SEND + ' ' + TOKEN_NAME,
);
});
});
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@
"update-changelog": "./scripts/auto-changelog.sh",
"prestorybook": "rnstl",
"create-release": "./scripts/set-versions.sh && yarn update-changelog",
"add-release-label-to-pr-and-linked-issues": "ts-node ./.github/scripts/add-release-label-to-pr-and-linked-issues.ts"
"add-release-label-to-pr-and-linked-issues": "ts-node ./.github/scripts/add-release-label-to-pr-and-linked-issues.ts",
"check-pr-has-required-labels": "ts-node ./.github/scripts/check-pr-has-required-labels.ts"
},
"husky": {
"hooks": {
Expand Down
Loading

0 comments on commit b46e7c9

Please sign in to comment.