-
Notifications
You must be signed in to change notification settings - Fork 942
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Task/Issue URL: https://app.asana.com/0/488551667048375/1209355305106376 ### Description Toll to flean up staled feature flags ### Steps to test this PR _Test_ - [ ] follow the steps in the [README](34ed3ed?short_path=0d4ef7f#diff-0d4ef7fd5e89570aa7a95aa2f6ce47d1719161b2ec8102a7daa7ca5716dffb16) file - [ ] Verify you can remove a feature flag setting its final value to `true` or `false`
- Loading branch information
Showing
4 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# Kotlin Feature Flag Cleanup CLI | ||
|
||
A command-line tool for cleaning up stale feature flags in Kotlin projects. | ||
|
||
## Installation | ||
|
||
Ensure you have **Python 3.12** installed. Clone the repository and install dependencies: | ||
|
||
```sh | ||
git clone https://github.com/duckduckgo/Android.git | ||
cd <path/to>/Android/scripts/piranha | ||
pip install -r requirements.txt | ||
``` | ||
|
||
## Requirements | ||
|
||
- Python 3.12 | ||
- Dependencies listed in `requirements.txt` | ||
|
||
### Step 1: Install Python 3.12 for your platform | ||
Windows: | ||
- Download Python 3.12 (https://www.python.org/downloads/release/python-3120/) and install it | ||
|
||
Linux: | ||
```sh | ||
sudo apt update | ||
sudo apt install python3.12 python3.12-venv | ||
``` | ||
|
||
MacOS: | ||
```sh | ||
brew install python@3.12 | ||
``` | ||
|
||
### Step 2: Create a Virtual Environment with Python 3.12 | ||
Windows: | ||
```sh | ||
py -3.12 -m venv myenv | ||
``` | ||
|
||
MacOS/Linux: | ||
```sh | ||
python3.12 -m venv myenv | ||
``` | ||
|
||
### Step 3: Activate the Virtual Environment | ||
Windows: | ||
```sh | ||
myenv\Scripts\activate | ||
``` | ||
|
||
MacOS/Linux | ||
```sh | ||
source myenv/bin/activate | ||
``` | ||
|
||
### Step 4: Verify Python Version Inside Virtual Environment | ||
```sh | ||
python --version | ||
``` | ||
|
||
## Usage | ||
|
||
```sh | ||
python clean.py [-h] -r ROOT_PATH -c CONFIGURATION_PATH -f FLAGS [FLAGS ...] | ||
``` | ||
|
||
## Options | ||
|
||
- `-h, --help` | ||
Show this help message and exit. | ||
|
||
- `-r ROOT_PATH, --root-path ROOT_PATH` | ||
Root path for searching Kotlin files. | ||
|
||
- `-c CONFIGURATION_PATH, --configuration-path CONFIGURATION_PATH` | ||
Path for the configuration files. | ||
|
||
- `-f FLAGS [FLAGS ...], --flags FLAGS [FLAGS ...]` | ||
Space-separated list of flag configurations in the format: | ||
`flagname:treated_value` (e.g., `'flag1:true flag2:false'`). | ||
|
||
## Explanation | ||
|
||
- **`configuration-path`**: Path to the `rules.toml` file containing cleanup rules. | ||
- **`root-path`**: The root path of your Android project. | ||
|
||
## Example Execution | ||
|
||
Assuming you're in the Android project folder, you can run: | ||
|
||
```sh | ||
python scripts/piranha/clean.py -r . -c scripts/piranha/configurations/ -f screenLock:false optimizeTrackerEvaluationV2:true | ||
``` | ||
|
||
This command runs the cleanup tool in the current directory (`.`), using the configuration files from `scripts/piranha/configurations/` and applying the flag transformations provided. | ||
|
||
## Notes | ||
|
||
- The script modifies Kotlin files based on the given flag configurations. | ||
- Use carefully, as it may remove or alter code. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import os | ||
import argparse | ||
import logging | ||
from os.path import join, dirname | ||
from polyglot_piranha import execute_piranha, PiranhaArguments | ||
|
||
# Set up logging | ||
FORMAT = "%(levelname)s %(name)s %(asctime)-15s %(filename)s:%(lineno)d %(message)s" | ||
logging.basicConfig(format=FORMAT) | ||
logging.getLogger().setLevel(logging.DEBUG) | ||
logger = logging.getLogger(__name__) | ||
|
||
def get_folders_with_kotlin_files(root_path): | ||
"""Finds all folders containing Kotlin (.kt) files starting from the given root path.""" | ||
folders_with_kt_files = [] | ||
|
||
for root, _, files in os.walk(root_path): | ||
if any(file.endswith('.kt') for file in files): | ||
folders_with_kt_files.append(root) | ||
|
||
return folders_with_kt_files | ||
|
||
def run_ff_cleaner(flags_config, root_path, configuration_path): | ||
"""Runs Piranha feature flag cleanup for Kotlin with the provided flag configurations and root path. | ||
Args: | ||
flags_config: List of tuples containing (flag_name, treated_value) | ||
root_path: Path to the root directory | ||
configuration_path: Path to configuration files | ||
""" | ||
logger.info("Running the stale feature flag cleanup demo for Kotlin") | ||
|
||
for flag_name, treated in flags_config: | ||
logger.info(f"Processing flag: {flag_name} with treated value: {treated}") | ||
# Convert treated to boolean (in case it's passed as a string) | ||
treated_bool = treated.lower() == "true" | ||
|
||
# Compute treated_complement programmatically | ||
treated_complement = "false" if treated_bool else "true" | ||
|
||
args = PiranhaArguments( | ||
"kt", | ||
substitutions={ | ||
"treated": str(treated_bool).lower(), | ||
"treated_complement": treated_complement, | ||
"flag_name": flag_name, | ||
}, | ||
allow_dirty_ast=True, | ||
paths_to_codebase=get_folders_with_kotlin_files(root_path), | ||
path_to_configurations=configuration_path, | ||
cleanup_comments=True, | ||
delete_consecutive_new_lines=True, | ||
) | ||
|
||
execute_piranha(args) | ||
logger.info(f"Piranha execution completed for flag: {flag_name}") | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description="Run stale feature flag cleanup for Kotlin.") | ||
parser.add_argument("-r", "--root-path", type=str, | ||
default=os.environ.get('FF_ROOT_PATH'), | ||
help="Root path for searching Kotlin files (default: $FF_ROOT_PATH)") | ||
parser.add_argument("-c", "--configuration-path", type=str, | ||
default=os.environ.get('FF_CLEAN_CONFIGURATION_PATH'), | ||
help="Path for the configuration files (default: $FF_CLEAN_CONFIGURATION_PATH)") | ||
parser.add_argument("-f", "--flags", type=str, required=True, nargs="+", | ||
help="Space-separated list of flag configurations in format: flagname:treated_value " + | ||
"(e.g., 'flag1:true flag2:false')") | ||
|
||
args = parser.parse_args() | ||
|
||
# Parse flag configurations | ||
flags_config = [] | ||
for flag_arg in args.flags: | ||
try: | ||
flag_name, treated = flag_arg.split(":") | ||
if treated.lower() not in ["true", "false"]: | ||
raise ValueError(f"Invalid treated value for flag {flag_name}: {treated}") | ||
flags_config.append((flag_name, treated)) | ||
except ValueError as e: | ||
parser.error(f"Invalid flag configuration format: {flag_arg}. Use format 'flagname:treated_value'. {str(e)}") | ||
|
||
run_ff_cleaner(flags_config, args.root_path, args.configuration_path) | ||
|
||
print("Completed running the stale feature flag cleanup demo") | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
[[rules]] | ||
name = "replace_isEnabled_with_boolean_literal" | ||
query = """( | ||
(call_expression | ||
(navigation_expression | ||
(call_expression | ||
(navigation_expression (_) (navigation_suffix (simple_identifier) @feature_call)) | ||
(call_suffix (value_arguments)) | ||
) | ||
(navigation_suffix (simple_identifier) @m_name) | ||
) | ||
(call_suffix) | ||
) @call_expression | ||
(#eq? @feature_call @flag_name) | ||
(#eq? @m_name "isEnabled") | ||
)""" | ||
replace_node = "call_expression" | ||
replace = "@treated" | ||
groups = ["replace_expression_with_boolean_literal"] | ||
holes = ["treated", "flag_name"] | ||
|
||
[[rules]] | ||
name = "delete_feature_flag" | ||
query = """( | ||
(class_declaration | ||
(class_body | ||
(function_declaration | ||
(simple_identifier) @feature_call | ||
(function_value_parameters) | ||
(user_type | ||
(type_identifier) @toggle_type | ||
) | ||
) @function_declaration | ||
) | ||
) | ||
(#eq? @feature_call @flag_name) | ||
(#eq? @toggle_type "Toggle") | ||
)""" | ||
replace_node = "function_declaration" | ||
replace = "" | ||
holes = ["flag_name"] | ||
groups = ["delete_feature_flag"] | ||
|
||
[[rules]] | ||
name = "remove_calls_onto_feature_flag" | ||
query = """( | ||
(call_expression | ||
(navigation_expression | ||
(call_expression | ||
(navigation_expression (_) (navigation_suffix (simple_identifier) @feature_call)) | ||
(call_suffix (value_arguments)) | ||
) | ||
(navigation_suffix (simple_identifier)) | ||
) | ||
(call_suffix) | ||
) @call_expression | ||
(#eq? @feature_call @flag_name) | ||
)""" | ||
replace_node = "call_expression" | ||
replace = "" | ||
groups = ["remove_calls_onto_feature_flag"] | ||
holes = ["flag_name"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
polyglot_piranha==0.3.29 |