konveyor / kai

Konveyor AI - static code analysis driven migration to new targets via Generative AI
Apache License 2.0
23 stars 28 forks source link

:sparkles: Adds a CLI frontend for kai #312

Closed fabianvf closed 2 weeks ago

fabianvf commented 3 weeks ago

Playing around with making kai a client-side tool rather than server-side tool. Just a quick hack.

$ kai/cli.py -h
usage: cli.py [-h] [-log {debug,info,warning,error,critical}] [-d | --demo-mode | --no-demo-mode] [-a APPLICATION_NAME] [-c CONFIG] [-r REPORT_PATH] [-i INCIDENTS] path

Get incident solutions for a file.

positional arguments:
  path                  The path to the file to be migrated

options:
  -h, --help            show this help message and exit
  -log {debug,info,warning,error,critical}, --loglevel {debug,info,warning,error,critical}
                        Provide logging level. Options: - debug: Detailed information, typically of interest only when diagnosing problems. - info: Confirmation that things are working as expected. - warning: An indication that something unexpected happened, or indicative of some problem in the near future (e.g.,
                        ‘disk space low’). The software is still working as expected. - error: Due to a more serious problem, the software has not been able to perform some function. - critical: A serious error, indicating that the program itself may be unable to continue running. Example: --loglevel debug
                        (default: warning)
  -d, --demo-mode, --no-demo-mode
  -a APPLICATION_NAME, --application-name APPLICATION_NAME
                        The name of the application
  -c CONFIG, --config CONFIG
                        The path to the config file
  -r REPORT_PATH, --report-path REPORT_PATH
                        Path to an analysis report. One of report-path or incidents are required
  -i INCIDENTS, --incidents INCIDENTS
                        JSON-formatted list of incidents. One of report-path or incidents are required

Example in use:

$ kai/cli.py --demo-mode --loglevel warning -c kai/config.toml -r example/analysis/coolstore/output.yaml example/coolstore/src/main/java/com/redhat/coolstore/rest/CartEndpoint.java
Console logging for 'kai' is set to level 'WARNING'
File logging for 'kai' is set to level 'DEBUG' writing to file: '/home/fabian/projects/github.com/konveyor-ecosystem/kai/logs/kai_server.log'
// Add import statements for jakarta.enterprise, jakarta.inject, and jakarta.ws.rs.
import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import com.redhat.coolstore.model.Product;
import com.redhat.coolstore.model.ShoppingCart;
import com.redhat.coolstore.model.ShoppingCartItem;
import com.redhat.coolstore.service.ShoppingCartService;

@SessionScoped
@Path("/cart")
public class CartEndpoint {

    // Add import statements for jakarta.ws.rs.
    import jakarta.ws.rs.core.MediaType;

    private static final long serialVersionUID = -7227732980791688773L;

    @Inject
    private ShoppingCartService shoppingCartService;

    @GET
    @Path("/{cartId}")
    @Produces(MediaType.APPLICATION_JSON)
    public ShoppingCart getCart(@PathParam("cartId") String cartId) {
        return shoppingCartService.getShoppingCart(cartId);
    }

    @POST
    @Path("/checkout/{cartId}")
    @Produces(MediaType.APPLICATION_JSON)
    public ShoppingCart checkout(@PathParam("cartId") String cartId) {
        return shoppingCartService.checkOutShoppingCart(cartId);
    }

    @POST
    @Path("/{cartId}/{itemId}/{quantity}")
    @Produces(MediaType.APPLICATION_JSON)
    public ShoppingCart add(@PathParam("cartId") String cartId,
                            @PathParam("itemId") String itemId,
                            @PathParam("quantity") int quantity) throws Exception {
        ShoppingCart cart = shoppingCartService.getShoppingCart(cartId);

        Product product = shoppingCartService.getProduct(itemId);

        ShoppingCartItem sci = new ShoppingCartItem();
        sci.setProduct(product);
        sci.setQuantity(quantity);
        sci.setPrice(product.getPrice());
        cart.addShoppingCartItem(sci);

        try {
            shoppingCartService.priceShoppingCart(cart);
            cart.setShoppingCartItemList(dedupeCartItems(cart.getShoppingCartItemList()));
        } catch (Exception ex) {
            cart.removeShoppingCartItem(sci);
            throw ex;
        }

        return cart;
    }

    @POST
    @Path("/{cartId}/{tmpId}")
    @Produces(MediaType.APPLICATION_JSON)
    public ShoppingCart set(@PathParam("cartId") String cartId,
                            @PathParam("tmpId") String tmpId) throws Exception {

        ShoppingCart cart = shoppingCartService.getShoppingCart(cartId);
        ShoppingCart tmpCart = shoppingCartService.getShoppingCart(tmpId);

        if (tmpCart != null) {
            cart.resetShoppingCartItemList();
            cart.setShoppingCartItemList(tmpCart.getShoppingCartItemList());
        }

        try {
            shoppingCartService.priceShoppingCart(cart);
            cart.setShoppingCartItemList(dedupeCartItems(cart.getShoppingCartItemList()));
        } catch (Exception ex) {
            throw ex;
        }

        return cart;
    }

    @DELETE
    @Path("/{cartId}/{itemId}/{quantity}")
    @Produces(MediaType.APPLICATION_JSON)
    public ShoppingCart delete(@PathParam("cartId") String cartId,
                               @PathParam("itemId") String itemId,
                               @PathParam("quantity") int quantity) throws Exception {

        List<ShoppingCartItem> toRemoveList = new ArrayList<>();

        ShoppingCart cart = shoppingCartService.getShoppingCart(cartId);

        cart.getShoppingCartItemList().stream()
                .filter(sci -> sci.getProduct().getItemId().equals(itemId))
                .forEach(sci -> {
                    if (quantity >= sci.getQuantity()) {
                        toRemoveList.add(sci);
                    } else {
                        sci.setQuantity(sci.getQuantity() - quantity);
                    }
                });

        toRemoveList.forEach(cart::removeShoppingCartItem);

        shoppingCartService.priceShoppingCart(cart);
        return cart;
    }

    private List<ShoppingCartItem> dedupeCartItems(List<ShoppingCartItem> cartItems) {
        List<ShoppingCartItem> result = new ArrayList<>();
        Map<String, Integer> quantityMap = new HashMap<>();
        for (ShoppingCartItem sci : cartItems) {
            if (quantityMap.containsKey(sci.getProduct().getItemId())) {
                quantityMap.put(sci.getProduct().getItemId(), quantityMap.get(sci.getProduct().getItemId()) + sci.getQuantity());
            } else {
                quantityMap.put(sci.getProduct().getItemId(), sci.getQuantity());
            }
        }

        for (String itemId : quantityMap.keySet()) {
            Product p = shoppingCartService.getProduct(itemId);
            ShoppingCartItem newItem = new ShoppingCartItem();
            newItem.setQuantity(quantityMap.get(itemId));
            newItem.setPrice(p.getPrice());
            newItem.setProduct(p);
            result.add(newItem);
        }
        return result;
    }
}
jwmatthews commented 2 weeks ago

@fabianvf I took what you have here as a starting point and extended it in #318 so that we can now run the cli like we did with run_demo.py, just minus the solved incidents.