-
-
Notifications
You must be signed in to change notification settings - Fork 5
Harry/mmqa ff drift and create pr #230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| name: Feature Flag Drift Report | ||
| description: 'Sends a Slack notification when feature flag drift is detected in E2E tests vs production.' | ||
|
|
||
| inputs: | ||
| title: | ||
| description: 'Project identifier shown in the message (e.g. MetaMask Extension, MetaMask Mobile)' | ||
| required: true | ||
| slack-webhook: | ||
| description: 'Slack incoming webhook URL' | ||
| required: true | ||
| workflow-run-url: | ||
| description: 'Full URL to the workflow run' | ||
| required: true | ||
| pr-url: | ||
| description: 'URL of the sync PR (optional; included in message when provided)' | ||
| required: false | ||
| default: '' | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Build Slack payload | ||
| id: payload | ||
| shell: bash | ||
| env: | ||
| TITLE: ${{ inputs.title }} | ||
| WORKFLOW_URL: ${{ inputs.workflow-run-url }} | ||
| PR_URL: ${{ inputs.pr-url }} | ||
| run: | | ||
| BASE="*[${TITLE}] Feature Flags Drift Detected in E2E tests vs Prod* :warning:\n\nCheck the workflow run for details: download the drift report JSON artifact and review the report.\n\nYou can run command \`yarn feature-flags:sync:update\` locally to update the registry.\n\n" | ||
| if [[ -n "$PR_URL" ]]; then | ||
| MSG="${BASE}A sync PR has been created: <${PR_URL}|View PR>\n\n<${WORKFLOW_URL}|View workflow run>" | ||
| else | ||
| MSG="${BASE}<${WORKFLOW_URL}|View workflow run>" | ||
| fi | ||
| PAYLOAD=$(jq -n --arg m "$MSG" '{text: $m, blocks: [{type: "section", text: {type: "mrkdwn", text: $m}}]}') | ||
| { | ||
| echo "payload<<EOF" | ||
| printf '%s\n' "$PAYLOAD" | ||
| echo "EOF" | ||
| } >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Send Slack notification | ||
| uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a | ||
| with: | ||
| webhook: ${{ inputs.slack-webhook }} | ||
| webhook-type: incoming-webhook | ||
| payload: ${{ steps.payload.outputs.payload }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| name: Create PR for Feature Flag Registry Drift | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| repository: | ||
| required: true | ||
| type: string | ||
| description: 'The repository name (e.g. metamask-extension)' | ||
| registry-file-path: | ||
| required: true | ||
| type: string | ||
| description: 'Path in the repo where the registry file lives (e.g. app/scripts/feature-flags/registry.json)' | ||
| registry-artifact-name: | ||
| required: true | ||
| type: string | ||
| description: 'Name of the artifact containing the updated registry file' | ||
| report-artifact-name: | ||
| required: true | ||
| type: string | ||
| description: 'Name of the artifact containing report.json' | ||
| pr-label: | ||
| required: false | ||
| type: string | ||
| default: '' | ||
| description: 'Label to apply to the created PR (must exist in the target repo)' | ||
| secrets: | ||
| github-token: | ||
| required: true | ||
| description: 'Token with contents write and pull-requests write permissions' | ||
| outputs: | ||
| pr-url: | ||
| description: 'URL of the created pull request (empty if no PR was created)' | ||
| value: ${{ jobs.create-drift-pr.outputs.pr-url }} | ||
| has-changes: | ||
| description: 'Whether the registry had drift that needed syncing' | ||
| value: ${{ jobs.create-drift-pr.outputs.has-changes }} | ||
|
|
||
| jobs: | ||
| create-drift-pr: | ||
| outputs: | ||
| pr-url: ${{ steps.create-pr.outputs.pr-url }} | ||
| has-changes: ${{ steps.commit.outputs.has_changes }} | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| token: ${{ secrets.github-token }} | ||
|
|
||
| - name: Download registry artifact | ||
| uses: actions/download-artifact@v7 | ||
| with: | ||
| name: ${{ inputs.registry-artifact-name }} | ||
| path: ${{ inputs.registry-artifact-name }} | ||
|
|
||
| - name: Download report artifact | ||
| uses: actions/download-artifact@v7 | ||
| with: | ||
| name: ${{ inputs.report-artifact-name }} | ||
| path: ${{ inputs.report-artifact-name }} | ||
|
|
||
| - name: Build PR body from report | ||
| id: pr-body | ||
| env: | ||
| REPORT_ARTIFACT: ${{ inputs.report-artifact-name }} | ||
| run: | | ||
| REPORT_FILE="$REPORT_ARTIFACT/report.json" | ||
| if [[ ! -f "$REPORT_FILE" ]]; then | ||
| REPORT_FILE=$(find "$REPORT_ARTIFACT" -name "report.json" -type f | head -1) | ||
| fi | ||
| if [[ -z "$REPORT_FILE" || ! -f "$REPORT_FILE" ]]; then | ||
| echo "::error::report.json not found in artifact $REPORT_ARTIFACT" | ||
| exit 1 | ||
| fi | ||
| { | ||
| echo "## Feature Flag Registry Drift Report" | ||
| echo "" | ||
| echo "The following drift was detected between E2E tests and production:" | ||
| echo "" | ||
| echo '```json' | ||
| cat "$REPORT_FILE" | ||
| echo '```' | ||
| } > pr-body.md | ||
|
|
||
| - name: Create branch and commit registry change | ||
| id: commit | ||
| env: | ||
| REPOSITORY: ${{ inputs.repository }} | ||
| REGISTRY_ARTIFACT: ${{ inputs.registry-artifact-name }} | ||
| REGISTRY_PATH: ${{ inputs.registry-file-path }} | ||
| run: | | ||
| BRANCH="qa/sync-ff-registry-$REPOSITORY" | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git checkout -b "$BRANCH" | ||
| mkdir -p "$(dirname "$REGISTRY_PATH")" | ||
| REGISTRY_SRC=$(find "./$REGISTRY_ARTIFACT" -name "$(basename "$REGISTRY_PATH")" -type f | head -1) | ||
| if [[ -z "$REGISTRY_SRC" ]]; then | ||
| echo "::error::No registry file found in artifact $REGISTRY_ARTIFACT" | ||
| exit 1 | ||
| fi | ||
| cp "$REGISTRY_SRC" "$REGISTRY_PATH" | ||
| git add "$REGISTRY_PATH" | ||
| git status | ||
| if git diff --staged --quiet; then | ||
| echo "::warning::No changes to registry file. Nothing to commit." | ||
| echo "has_changes=false" >> "$GITHUB_OUTPUT" | ||
| else | ||
| git commit -m "chore: sync feature flag registry from E2E" | ||
| git push --force-with-lease origin "$BRANCH" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Force-with-lease fails when remote branch already existsMedium Severity
Additional Locations (1) |
||
| echo "has_changes=true" >> "$GITHUB_OUTPUT" | ||
| echo "branch=$BRANCH" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - name: Create Pull Request | ||
| id: create-pr | ||
| if: steps.commit.outputs.has_changes == 'true' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.github-token }} | ||
| REPOSITORY: ${{ inputs.repository }} | ||
| BRANCH: ${{ steps.commit.outputs.branch }} | ||
| PR_LABEL: ${{ inputs.pr-label }} | ||
| run: | | ||
| EXISTING=$(gh pr list --head "$BRANCH" --state open --json url --jq '.[0].url' 2>/dev/null || true) | ||
| if [[ -n "$EXISTING" ]]; then | ||
| echo "pr-url=$EXISTING" >> "$GITHUB_OUTPUT" | ||
| exit 0 | ||
| fi | ||
| LABEL_ARGS=() | ||
| if [[ -n "$PR_LABEL" ]]; then | ||
| LABEL_ARGS=(--label "$PR_LABEL") | ||
| fi | ||
| PR_URL=$(gh pr create \ | ||
| --title "[QA] Sync Feature Flag Registry ($REPOSITORY)" \ | ||
| --body-file pr-body.md \ | ||
| --base main \ | ||
| --head "$BRANCH" \ | ||
| "${LABEL_ARGS[@]}") | ||
| echo "pr-url=$PR_URL" >> "$GITHUB_OUTPUT" | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slack message shows literal
\ninstead of newlinesLow Severity
The
\nsequences in theBASEandMSGbash variables are literal two-character strings (backslash + n), not actual newlines. When passed tojq --arg, each backslash is JSON-escaped to\\, producing\\nin the JSON output. After Slack's JSON parser decodes this, the text contains literal\ncharacters. Slack'smrkdwnformat does not interpret these as line breaks, so the entire message renders as a single unformatted block.