262 lines
12 KiB
YAML
262 lines
12 KiB
YAML
name: Feature Flag Cleanup
|
|
|
|
on:
|
|
schedule:
|
|
- cron: '0 15 * * *' # 10am EST
|
|
workflow_dispatch:
|
|
|
|
# Default to a read-only token. Jobs that need to push or open PRs widen
|
|
# permissions explicitly below.
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
analyze:
|
|
name: Analyze feature flags
|
|
runs-on: namespace-profile-ubuntu-small
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
outputs:
|
|
flag_name: ${{ steps.select_flag.outputs.flag_name }}
|
|
cargo_flag: ${{ steps.select_flag.outputs.cargo_flag }}
|
|
reviewers: ${{ steps.select_flag.outputs.reviewers }}
|
|
analyzed_sha: ${{ steps.record_sha.outputs.analyzed_sha }}
|
|
artifact_url: ${{ steps.upload_feature_flag_log.outputs.artifact-url }}
|
|
steps:
|
|
- name: Check out code
|
|
uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Record analyzed commit
|
|
id: record_sha
|
|
run: |
|
|
echo "analyzed_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Find old feature flags
|
|
uses: warpdotdev/oz-agent-action@main
|
|
with:
|
|
prompt: |
|
|
Your task is to find and list any feature flags which have been enabled by default for more than 3 months.
|
|
|
|
There will always be at least one such flag.
|
|
|
|
## Context
|
|
Feature flags are defined in warp_core/src/features.rs. They're enabled by default in app/Cargo.toml, using the default feature list. The mapping between Cargo features and app features is in the enabled_features function of app/src/lib.rs.
|
|
|
|
## Recommended Procedure
|
|
1. Use `git blame` on the Cargo.toml file to identify when each feature flag was enabled by default.
|
|
2. Read the enabled_features function to map Cargo features to app features.
|
|
3. Write features that have been enabled by default for more than 3 months to the output file.
|
|
|
|
You may create temporary files to store useful results, and write helper scripts for subtasks. It is not necessary to do everything in one shot.
|
|
|
|
## Result Format
|
|
List the old feature flags in ${{ runner.temp }}/flags_to_cleanup.jsonl, in this format (one flag per line):
|
|
{ "flag_name": "MyFlag", "cargo_flag": "my_flag", "date_enabled": "2025-02-21", "enabling_commit": "aad3293b8fe" }
|
|
|
|
## Reminders
|
|
* Fields in the output JSONL file have these meanings:
|
|
* "flag_name" - the name of the FeatureFlag enum variant
|
|
* "cargo_flag" - the name of the flag used in Cargo.toml
|
|
* "date_enabled" - the date on which the feature flag was enabled by default
|
|
* "enabling_commit" - the Git commit in which the feature flag was enabled by default
|
|
* You are running as part of a GitHub automation and must not commit or push any changes. Another agent will process the file you produce.
|
|
warp_api_key: ${{ secrets.WARP_API_KEY }}
|
|
share: team
|
|
|
|
- name: Upload feature flag log
|
|
id: upload_feature_flag_log
|
|
uses: namespace-actions/upload-artifact@f6ccaacc655aec41b93af180d1d7eef21af862d2 # v1.0.3
|
|
with:
|
|
name: flags-to-cleanup
|
|
path: ${{ runner.temp }}/flags_to_cleanup.jsonl
|
|
|
|
# As we test out the workflow, only clean up one flag at a time.
|
|
# We could also pick several flags, or fan out jobs for every single one.
|
|
- name: Select a flag to clean up
|
|
id: select_flag
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
cleanup_log="$RUNNER_TEMP/flags_to_cleanup.jsonl"
|
|
# Skip over flags that are also used to enable/disable functionality at runtime.
|
|
excluded_flags='["CreatingSharedSessions", "ViewingSharedSessions", "AgentMode"]'
|
|
|
|
flag_name=""
|
|
cargo_flag=""
|
|
|
|
# Iterate flags in order (oldest first) and pick the first one that is not
|
|
# excluded and does not already have an open cleanup PR. Sort by
|
|
# date_enabled here rather than relying on the analysis agent to emit
|
|
# the JSONL in any particular order.
|
|
while IFS= read -r candidate; do
|
|
[ -z "$candidate" ] && continue
|
|
candidate_flag="$(jq -r '.flag_name' <<< "$candidate")"
|
|
|
|
if [ "$(jq -n --arg flag "$candidate_flag" --argjson excluded "$excluded_flags" '$excluded | index($flag) != null')" = "true" ]; then
|
|
echo "Skipping $candidate_flag: in excluded list"
|
|
continue
|
|
fi
|
|
|
|
candidate_branch="oz-agent/cleanup-feature-flag-$candidate_flag"
|
|
existing_pr="$(gh pr list --state open --head "$candidate_branch" --json number --jq '.[0].number')"
|
|
if [ -n "$existing_pr" ] && [ "$existing_pr" != "null" ]; then
|
|
echo "Skipping $candidate_flag: open cleanup PR #$existing_pr already exists on $candidate_branch"
|
|
continue
|
|
fi
|
|
|
|
flag_name="$candidate_flag"
|
|
cargo_flag="$(jq -r '.cargo_flag' <<< "$candidate")"
|
|
break
|
|
done < <(jq -c -s 'sort_by(.date_enabled) | .[]' "$cleanup_log")
|
|
echo "flag_name=$flag_name" >> "$GITHUB_OUTPUT"
|
|
echo "cargo_flag=$cargo_flag" >> "$GITHUB_OUTPUT"
|
|
|
|
echo "Cleaning up $flag_name ($cargo_flag)"
|
|
|
|
if [ -z "$flag_name" ] || [ "$flag_name" = "null" ]; then
|
|
echo "No flag selected for cleanup"
|
|
echo "reviewers=" >> "$GITHUB_OUTPUT"
|
|
else
|
|
enabling_commit="$(jq -r -cs --arg flag "$flag_name" '.[] | select(.flag_name == $flag) | .enabling_commit' "$cleanup_log")"
|
|
committer_username=""
|
|
|
|
# Resolve the GitHub username of the commit author directly via the
|
|
# commits API. This is more reliable than mapping a commit email to
|
|
# a GitHub user, since commit emails are often noreply addresses or
|
|
# otherwise unsearchable.
|
|
if [ -n "$enabling_commit" ] && [ "$enabling_commit" != "null" ]; then
|
|
committer_username="$(gh api "repos/${{ github.repository }}/commits/$enabling_commit" --jq '.author.login // ""' 2>/dev/null || echo "")"
|
|
fi
|
|
|
|
default_reviewers="bennavetta"
|
|
|
|
# Verify the committer is still a collaborator before assigning as reviewer.
|
|
if [ -n "$committer_username" ] && gh api "repos/${{ github.repository }}/collaborators/$committer_username" --verbose 2>/dev/null; then
|
|
echo "Flag originally enabled by $committer_username"
|
|
echo "reviewers=$committer_username,$default_reviewers" >> "$GITHUB_OUTPUT"
|
|
elif [ -n "$committer_username" ]; then
|
|
echo "$committer_username is no longer a collaborator, using fallback"
|
|
echo "reviewers=$default_reviewers" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "Could not determine flag committer, using fallback"
|
|
echo "reviewers=$default_reviewers" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
fi
|
|
|
|
cleanup:
|
|
name: Run cleanup agent
|
|
needs: analyze
|
|
if: ${{ needs.analyze.outputs.flag_name && needs.analyze.outputs.flag_name != 'null' }}
|
|
runs-on: namespace-profile-ubuntu-small
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Check out code
|
|
uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1
|
|
with:
|
|
ref: ${{ needs.analyze.outputs.analyzed_sha }}
|
|
fetch-depth: 0
|
|
|
|
- name: Setup Rust cache
|
|
uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2
|
|
with:
|
|
cache: rust
|
|
|
|
- name: Clean up the unused feature flag
|
|
id: cleanup_agent
|
|
uses: warpdotdev/oz-agent-action@main
|
|
with:
|
|
prompt: |
|
|
The feature flag ${{ needs.analyze.outputs.flag_name }} is now enabled by default.
|
|
|
|
Clean up all references to this flag, modifying code to always assume it is enabled. Ensure that the code is correctly formatted and that tests still pass.
|
|
|
|
Finally, remove the flag from the `FeatureFlag` enum, and remove the equivalent ${{ needs.analyze.outputs.cargo_flag }} feature in app/Cargo.toml
|
|
|
|
You are running as part of a GitHub automation that runs with a read-only token and will package your changes into a patch for a separate job to commit. Do not create a branch, do not commit, do not push, do not create a PR, and do not call `gh`. Leave your changes in the working tree only.
|
|
share: team
|
|
warp_api_key: ${{ secrets.WARP_API_KEY }}
|
|
|
|
- name: Generate cleanup patch
|
|
env:
|
|
ANALYZED_SHA: ${{ needs.analyze.outputs.analyzed_sha }}
|
|
run: |
|
|
# If the cleanup agent made any local commits, undo them while keeping
|
|
# the changes in the working tree, so the resulting patch reflects the
|
|
# full set of changes relative to the analyzed commit.
|
|
git reset --mixed "$ANALYZED_SHA"
|
|
# Stage all changes (modified, new, deleted) so the patch is complete.
|
|
git add -A
|
|
git diff --staged --binary > "$RUNNER_TEMP/cleanup.patch"
|
|
if [ ! -s "$RUNNER_TEMP/cleanup.patch" ]; then
|
|
echo "Cleanup agent produced no changes" >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Upload cleanup patch
|
|
uses: namespace-actions/upload-artifact@f6ccaacc655aec41b93af180d1d7eef21af862d2 # v1.0.3
|
|
with:
|
|
name: cleanup-patch
|
|
path: ${{ runner.temp }}/cleanup.patch
|
|
|
|
create_pr:
|
|
name: Create cleanup PR
|
|
needs: [analyze, cleanup]
|
|
if: ${{ needs.analyze.outputs.flag_name && needs.analyze.outputs.flag_name != 'null' }}
|
|
runs-on: namespace-profile-ubuntu-small
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
steps:
|
|
- name: Check out code
|
|
uses: namespacelabs/nscloud-checkout-action@938f5d2d403d6224d9a0c0dc559b1dae09c2ede4 # v8.1.1
|
|
with:
|
|
ref: ${{ needs.analyze.outputs.analyzed_sha }}
|
|
fetch-depth: 0
|
|
|
|
- name: Download cleanup patch
|
|
uses: namespace-actions/download-artifact@7cbad919e4b0e09f17e9d6311a444ff002992b5b # v2.0.1
|
|
with:
|
|
name: cleanup-patch
|
|
path: ${{ runner.temp }}
|
|
|
|
- name: Apply cleanup patch
|
|
run: |
|
|
git apply --binary --whitespace=nowarn "$RUNNER_TEMP/cleanup.patch"
|
|
|
|
- name: Create Pull Request
|
|
id: create_pr
|
|
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
|
with:
|
|
token: ${{ github.token }}
|
|
base: ${{ github.event.repository.default_branch }}
|
|
commit-message: "Clean up ${{ needs.analyze.outputs.flag_name }} feature flag"
|
|
branch: "oz-agent/cleanup-feature-flag-${{ needs.analyze.outputs.flag_name }}"
|
|
author: "Oz Agent <oz-agent@warp.dev>"
|
|
delete-branch: true
|
|
reviewers: ${{ needs.analyze.outputs.reviewers }}
|
|
title: "Clean up ${{ needs.analyze.outputs.flag_name }} feature flag"
|
|
body: |
|
|
Automated cleanup of the `${{ needs.analyze.outputs.flag_name }}` feature flag.
|
|
|
|
This PR was generated by the feature flag cleanup workflow.
|
|
|
|
- run: |
|
|
echo "Full feature flag analysis results: ${{ needs.analyze.outputs.artifact_url }}"
|
|
echo "Pull request created: ${{ steps.create_pr.outputs.pull-request-url }}"
|
|
|
|
- name: Send Slack notification
|
|
uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
|
|
if: ${{ steps.create_pr.outputs.pull-request-operation == 'created' }}
|
|
with:
|
|
method: chat.postMessage
|
|
token: ${{ secrets.ACTION_MONITORING_SLACK }}
|
|
payload: |
|
|
channel: "#oncall-client"
|
|
# Follows https://api.slack.com/reference/surfaces/formatting#mentioning-users.
|
|
# S09SSGE729E is the user group ID for @eng-warp-3.
|
|
text: "🧹 New feature flag cleanup PR for `${{ needs.analyze.outputs.flag_name }}`: ${{ steps.create_pr.outputs.pull-request-url }}! <!subteam^S09SSGE729E> please review\nSee logs at https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|