Skip to content
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

Feature/url show and repeat history #201

Closed

Conversation

Xouzoura
Copy link
Contributor

@Xouzoura Xouzoura commented Oct 7, 2024

WHAT

Added two features that I have made that might be helpful for others.

  • Re-run last query that was made (helpful so that this can be done anywhere and not a specific hurl file) through the HurlRerun
  • Add the url in the headers to know against which endpoint the hurl command was run (found it difficult to check).

WHY

Not sure if that's needed, but for me I find quite helpful to be able to rerun last request without having to go to the hurl file. Then if you make a change anywhere, you can rerun and the hurl command and see the results.

For the url, I think it makes sense to be able to see the url of the request in the endpoint headers (especially when this is not a localhost where you can see directly, but also makes easier to copy paste things. Not sure if it should go on the headers, added it there for simplicity.

So feel free to reject if you find this redundant.

HOW

  • The rerun is done by caching with deepcopy the last opts through the HurlRerun command.
  • The url acquisition is done by using the hurl file and finding the GET/POST/PUT/DELETE and using that url. Bonus is that if something is parameterized, you have the option to select if you want the proper url or the parameterized url, based on the global config. Example:
    url | GET {{HOST}}/user/group-accesses
    or
    url | GET localhost:8000/user/group-accesses

Screenshots (if appropriate):

Screenshot from 2024-10-07 11-11-34

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • Linter
  • Tests
  • Review comments
  • Security

Important

Add rerun command and URL display feature to Hurl plugin, enhancing request management and visibility.

  • Features:
    • Add HurlRerun command in main.lua to rerun the last executed request using cached options.
    • Display request URL in response headers in popup.lua and split.lua if url.show is enabled in config.
  • Configuration:
    • Add url config in init.lua with options show and format_without_params.
  • Utilities:
    • Implement get_url_from_hurl_file() and convert_url_to_proper_format() in utils.lua to extract and format URLs from Hurl files.

This description was created by Ellipsis for d7e952a. It will automatically update as commits are pushed.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new url configuration for enhanced URL handling.
    • Added a HurlRerun command to easily rerun the last executed HTTP request.
  • Improvements

    • Enhanced header population to include URLs in responses.
    • Improved overall usability of the Hurl command with better request management.

Copy link

codesandbox bot commented Oct 7, 2024

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

Copy link

changeset-bot bot commented Oct 7, 2024

⚠️ No Changeset found

Latest commit: 0118867

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

coderabbitai bot commented Oct 7, 2024

Walkthrough

The changes in this pull request introduce enhancements to the hurl.nvim plugin, focusing on URL handling and request management. A new url table is added to the default_config, allowing for specific URL settings. The main.lua file is updated to store the last request options, enabling a rerun feature through the new HurlRerun command. Modifications in popup.lua and split.lua ensure that the URL is included in the headers when available.

Changes

File Path Change Summary
lua/hurl/init.lua Added new url table in default_config: url = { show = true, format_without_params = true }
lua/hurl/main.lua Added variable last_request_opts and command HurlRerun. Updated execute_hurl_cmd and run_lines functions to utilize last_request_opts.
lua/hurl/popup.lua Modified M.show function to include data.url in data.headers if data.url exists.
lua/hurl/split.lua Modified M.show function to include data.url in data.headers if data.url exists.

Poem

In the burrow where requests do play,
A new url table brightens the day.
With HurlRerun, we leap and bound,
Fetching URLs where they're found.
So hop along, dear friends, let's cheer,
For smoother requests, the time is near! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Changes requested. Reviewed everything up to d7e952a in 29 seconds

More details
  • Looked at 203 lines of code in 5 files
  • Skipped 0 files when reviewing.
  • Skipped posting 3 drafted comments based on config settings.
1. lua/hurl/utils.lua:342
  • Draft comment:
    The convert_url_to_proper_format function assumes the environment file is always specified in options. Consider adding error handling for cases where the environment file is missing or incorrectly specified.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable:
    The comment is relevant to the changes made in the diff, as it addresses a potential issue in the newly added convert_url_to_proper_format function. The function does log an error if the environment file cannot be opened, but it does not handle the case where the environment file is missing from the options, which the comment suggests addressing.
    The function does log an error if the environment file cannot be opened, which might be considered a form of error handling. However, the comment suggests a more robust handling of the situation, which could be beneficial.
    While logging an error is a form of error handling, the comment suggests a more comprehensive approach, which could improve the robustness of the function.
    The comment is valid and relevant to the changes made in the diff. It suggests a potential improvement in error handling for the convert_url_to_proper_format function.
2. lua/hurl/main.lua:129
  • Draft comment:
    The last_request_opts variable is set in multiple places (execute_hurl_cmd and run_lines). Consider centralizing the logic for setting this variable to ensure consistency and avoid potential issues.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable:
    The comment points out a potential code quality issue that could lead to inconsistencies. Centralizing the logic for setting last_request_opts could improve maintainability and reduce the risk of errors. This is a valid suggestion for a code quality refactor.
    The comment does not specify how to centralize the logic, which might make it less actionable. However, it still highlights a potential issue that could be addressed.
    Even though the comment does not provide a specific solution, it identifies a valid concern that could improve the code's maintainability.
    The comment is valid as it highlights a potential issue with setting last_request_opts in multiple places. It should be kept as it suggests a code quality improvement.
3. lua/hurl/main.lua:598
  • Draft comment:
    In the HurlRerun command, if last_request_opts is not set, consider notifying the user instead of just logging the message. This would improve user feedback.
  • Reason this comment was not posted:
    Confidence changes required: 50%
    The HurlRerun command is defined to rerun the last request using last_request_opts. However, if last_request_opts is not set, it logs a message but does not notify the user. Adding a notification would improve user feedback.

Workflow ID: wflow_3BHhHdS3CsVExQYy


Want Ellipsis to fix these issues? Tag @ellipsis-dev in a comment. You can customize Ellipsis with 👍 / 👎 feedback, review rules, user-specific overrides, quiet mode, and more.

@@ -312,5 +312,80 @@ util.has_file_in_opts = function(opts)

return false
end
-- Function to extract the URL from the .hurl file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_url_from_hurl_file function may not accurately extract URLs if the line contains more than just the URL or if the URL is split across lines. Consider improving the logic to extract only the URL part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If as a concept the PR is liked and this is an issue, I can improve that. It works for single line urls currently, but it is right that it might have an issue if you split (if somebody splits the url ofc).

Let me know

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Xouzoura Thank you for your PR. Yeah, I like your idea on this. Could you please check and fix the review bots when you're available? 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jellydn Cool! Had no time so far, I will try this weekend.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
lua/hurl/init.lua (1)

8-11: LGTM! Consider adding inline documentation.

The new url configuration is well-structured and aligns with the PR objectives. It provides useful defaults for showing URLs and formatting them without parameters.

Consider adding inline documentation to explain the purpose of these options:

url = {
  -- Whether to show the URL in headers
  show = true,
  -- Whether to format the URL without query parameters
  format_without_params = true,
},

This will help users understand the purpose of these configuration options without needing to refer to external documentation.

lua/hurl/split.lua (1)

37-39: LGTM! Consider adding a safety check.

The addition of the URL to the headers aligns well with the PR objectives, enhancing the functionality without disrupting existing behavior. This change will indeed make it easier for users to identify which endpoint was used for the request.

Consider adding a safety check to ensure data.headers is a table before assigning to it. This can prevent potential errors if data.headers is unexpectedly nil or not a table. Here's a suggested implementation:

 if data.url then
+  if type(data.headers) ~= "table" then
+    data.headers = {}
+  end
   data.headers['url'] = data.url
 end

This change ensures that data.headers is always a table before we attempt to add the URL to it.

lua/hurl/popup.lua (1)

86-88: LGTM! Consider adding a comment for clarity.

The addition of the URL to the headers when available is a good enhancement, aligning well with the PR objectives. It improves the information displayed in the popup, making it easier for users to identify the endpoint.

Consider adding a brief comment explaining the purpose of this addition for better code readability:

+  -- Include the URL in headers for better visibility in the popup
   if data.url then
     data.headers['url'] = data.url
   end
lua/hurl/main.lua (3)

136-136: LGTM: Updates to execute_hurl_cmd function

The changes effectively implement the rerun feature and URL display functionality. The use of configuration settings for URL display provides good flexibility.

Consider adding a comment explaining the purpose of last_request_opts for better code readability.

+-- Store the current request options for potential rerun
 last_request_opts = opts

Also applies to: 207-213


598-607: LGTM: Addition of HurlRerun command

The HurlRerun command is well-implemented, utilizing the stored last request options and including a necessary check.

Consider adding a user notification when there's no last request to rerun for better user experience.

 if last_request_opts then
   run_lines(last_request_opts, {})
 else
   utils.log_info('No last request to re-run')
+  utils.notify('No last request to re-run', vim.log.levels.INFO)
 end

Line range hint 129-607: Overall implementation looks good

The new features (rerun functionality and URL display in headers) are well-implemented and integrated into the existing codebase. They align with the PR objectives and offer good flexibility through configuration settings.

Some suggestions for further improvement:

  1. Consider adding more detailed comments explaining the purpose and functionality of the new features.
  2. It might be beneficial to add some error handling for edge cases, such as when the stored request options become invalid.
  3. Think about adding unit tests for the new functionalities to ensure their reliability.
lua/hurl/utils.lua (1)

343-344: Remove unnecessary comment

The comment -- Assuming 'url' is defined earlier in the code is unnecessary since url is a parameter to the function.

Apply this diff to remove the comment:

 util.convert_url_to_proper_format = function(opts, url)
-  -- Assuming `url` is defined earlier in the code
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 807b6ff and d7e952a.

📒 Files selected for processing (5)
  • lua/hurl/init.lua (1 hunks)
  • lua/hurl/main.lua (4 hunks)
  • lua/hurl/popup.lua (1 hunks)
  • lua/hurl/split.lua (1 hunks)
  • lua/hurl/utils.lua (1 hunks)
🧰 Additional context used
🔇 Additional comments (3)
lua/hurl/popup.lua (1)

Line range hint 1-188: Overall, the changes enhance functionality without disrupting existing code.

The modification to include the URL in the headers is well-integrated into the existing M.show function. It achieves the PR objective of providing better visibility of the endpoint while maintaining code consistency and not introducing any apparent issues.

lua/hurl/main.lua (2)

129-129: LGTM: Addition of last_request_opts variable

The introduction of this variable is a good foundation for implementing the rerun feature. It's correctly scoped as a local variable.


312-312: LGTM: Update to run_lines function

The addition of storing the last request lines using vim.deepcopy is a good implementation. It ensures data integrity for the rerun feature when dealing with selections or specific line ranges.

Comment on lines 325 to 330
local matchcase = string.find(line, 'GET ')
or string.find(line, 'POST ')
or string.find(line, 'PUT ')
or string.find(line, 'DELETE ')
or string.find(line, 'PATCH ')
if matchcase then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify HTTP method matching logic

Consider using pattern matching or a table to simplify the HTTP method detection, improving readability and maintainability.

Apply this diff to refactor the code:

         line = line:gsub('%s+', ' ')
-        -- NOTE: somehow i can not make regex work here
-        local matchcase = string.find(line, 'GET ')
-          or string.find(line, 'POST ')
-          or string.find(line, 'PUT ')
-          or string.find(line, 'DELETE ')
-          or string.find(line, 'PATCH ')
-        if matchcase then
+        local method = line:match('^(%w+)%s')
+        local http_methods = { GET = true, POST = true, PUT = true, DELETE = true, PATCH = true }
+        if http_methods[method] then
           file:close()
           return line
         end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
local matchcase = string.find(line, 'GET ')
or string.find(line, 'POST ')
or string.find(line, 'PUT ')
or string.find(line, 'DELETE ')
or string.find(line, 'PATCH ')
if matchcase then
line = line:gsub('%s+', ' ')
local method = line:match('^(%w+)%s')
local http_methods = { GET = true, POST = true, PUT = true, DELETE = true, PATCH = true }
if http_methods[method] then

Comment on lines 320 to 331
if file then
for line in file:lines() do
line = line:gsub('^%s*(.-)%s*$', '%1')
line = line:gsub('%s+', ' ')
-- NOTE: somehow i can not make regex work here
local matchcase = string.find(line, 'GET ')
or string.find(line, 'POST ')
or string.find(line, 'PUT ')
or string.find(line, 'DELETE ')
or string.find(line, 'PATCH ')
if matchcase then
return line
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix potential file descriptor leak on early return

In util.get_url_from_hurl_file, if a match is found, the function returns immediately without closing the file, which could lead to a file descriptor leak.

Apply this diff to ensure the file is closed properly:

 for line in file:lines() do
   line = line:gsub('^%s*(.-)%s*$', '%1')
   line = line:gsub('%s+', ' ')
   -- NOTE: somehow i can not make regex work here
   local matchcase = string.find(line, 'GET ')
     or string.find(line, 'POST ')
     or string.find(line, 'PUT ')
     or string.find(line, 'DELETE ')
     or string.find(line, 'PATCH ')
   if matchcase then
+    file:close()
     return line
   end
 end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if file then
for line in file:lines() do
line = line:gsub('^%s*(.-)%s*$', '%1')
line = line:gsub('%s+', ' ')
-- NOTE: somehow i can not make regex work here
local matchcase = string.find(line, 'GET ')
or string.find(line, 'POST ')
or string.find(line, 'PUT ')
or string.find(line, 'DELETE ')
or string.find(line, 'PATCH ')
if matchcase then
return line
if file then
for line in file:lines() do
line = line:gsub('^%s*(.-)%s*$', '%1')
line = line:gsub('%s+', ' ')
-- NOTE: somehow i can not make regex work here
local matchcase = string.find(line, 'GET ')
or string.find(line, 'POST ')
or string.find(line, 'PUT ')
or string.find(line, 'DELETE ')
or string.find(line, 'PATCH ')
if matchcase then
file:close()
return line

@jellydn
Copy link
Owner

jellydn commented Oct 7, 2024

Thanks @Xouzoura This is nice idea. Could you please check the review bot and fix if any issue? I will give it a try whenever you're done.

@Xouzoura
Copy link
Contributor Author

Xouzoura commented Oct 7, 2024

@jellydn Sure, will probably do it though around end of the work-week. It should be working in general if you wanna try this out and get a feeling of it, but will need to check for the multi-line url if that's possible and what to do (can probably check and allow it only if single line for the time being or something).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d7e952a and d4dffb6.

📒 Files selected for processing (1)
  • lua/hurl/utils.lua (1 hunks)
🧰 Additional context used
🔇 Additional comments (4)
lua/hurl/utils.lua (4)

331-333: Fix potential file descriptor leak

As previously noted in a past review comment, there's a potential file descriptor leak if a match is found early in the file. The file is closed here, but not in the main loop. Consider moving the file:close() call outside the loop to ensure it's always closed, regardless of whether a match is found.

Apply this diff to fix the issue:

    for line in file:lines() do
      -- ... (existing code)
      if matchcase then
-        file:close()
         return line
       end
     end
+    file:close()

This ensures that the file is always closed after processing, preventing resource leaks.


315-391: Summary of changes and suggestions

The new functions get_url_from_hurl_file and convert_url_to_proper_format add valuable URL handling and environment variable substitution capabilities to the utility module. These additions align well with the PR objectives of enhancing user experience and streamlining workflows.

Key points from the review:

  1. Improved HTTP method matching in get_url_from_hurl_file using Lua's pattern matching.
  2. Addressed potential file descriptor leak.
  3. Suggested optimizations for convert_url_to_proper_format, including modularization and error handling improvements.
  4. Recommended security enhancements for environment variable handling.

These changes, along with the suggested improvements, will significantly enhance the functionality and robustness of the hurl.nvim plugin. Please consider implementing the proposed refactors and running the provided verification scripts to ensure the changes work as expected.


343-391: Consider security implications of environment variable substitution

While the current implementation provides flexibility, it's important to be aware of potential security implications:

  1. Ensure that the .env files are not accidentally committed to version control systems.
  2. Be cautious about the sources of environment variables, especially if they're used in sensitive contexts (e.g., database connections).
  3. Consider implementing a whitelist of allowed environment variables to prevent accidental exposure of sensitive information.

To enhance security:

  1. Add a comment at the top of the function warning about potential security risks.
  2. Implement a whitelist mechanism for allowed environment variables.

Example implementation:

local ALLOWED_ENV_VARS = {
  'HOST', 'PORT', 'PATH', 'SCHEME'
  -- Add other allowed variables here
}

-- ... (in the parse_env_file function)
if key and value and ALLOWED_ENV_VARS[key] then
  env_vars[key] = value:gsub('^["\'](.-)["\']\s*$', '%1')
else
  util.log_info('Skipping disallowed or malformed environment variable: ' .. (key or 'unknown'))
end

This change ensures that only pre-approved environment variables are used in URL substitution, reducing the risk of accidentally exposing sensitive information.

To verify this security enhancement, run the following script:

#!/bin/bash
# Test the URL conversion function with security enhancements

# Mock the util.log_error and util.log_info functions
function util.log_error() {
  echo "ERROR: $1" >&2
}

function util.log_info() {
  echo "INFO: $1" >&2
}

# Test cases
test_cases=(
  "http://{{HOST}}/api/v1/users"
  "https://{{HOST}}:{{PORT}}/{{PATH}}"
  "{{SCHEME}}://{{HOST}}/{{SENSITIVE_DATA}}"
)

# Mock .env file content
cat << EOF > test.env
HOST=example.com
PORT=8080
PATH=api/v2
SCHEME=https
SENSITIVE_DATA=password123
EOF

# Run tests
for url in "${test_cases[@]}"; do
  echo "Testing URL: $url"
  lua -e "
    local util = require('lua.hurl.utils')
    print(util.convert_url_to_proper_format({'test.env'}, '$url'))
  "
  echo
done

# Clean up
rm test.env

This script will help verify that the security enhancements prevent the use of non-whitelisted environment variables (like SENSITIVE_DATA) in URL substitution.


343-391: 🛠️ Refactor suggestion

Optimize URL conversion and improve error handling

The convert_url_to_proper_format function has a good overall structure, but there are opportunities for optimization and improved error handling:

  1. Consider moving the .env file search and parsing into a separate function for better modularity.
  2. Use pcall when opening and reading the file to handle potential I/O errors gracefully.
  3. The URL substitution could be done more efficiently using a single gsub call with a function.

Here's a suggested refactor:

local function parse_env_file(file_path)
  local env_vars = {}
  local success, file = pcall(io.open, file_path, 'r')
  if not success then
    util.log_error('Could not open environment file: ' .. file_path)
    return env_vars
  end
  for line in file:lines() do
    local key, value = line:match('^%s*([^#%s][^=]+)%s*=%s*(.+)$')
    if key and value then
      env_vars[key] = value:gsub('^["\'](.-)["\']\s*$', '%1')
    end
  end
  file:close()
  return env_vars
end

util.convert_url_to_proper_format = function(opts, url)
  if not (url and url:find('{{')) then return url end

  local env_file = opts[1]:match('%.env$') and opts[1] or nil
  if not env_file then
    util.log_error('No environment file found in opts.')
    return url
  end

  local env_vars = parse_env_file(env_file)
  return url:gsub('{{(.-)}}', function(key)
    return env_vars[key] or '{{' .. key .. '}}'
  end)
end

This refactored version improves error handling, reduces code duplication, and optimizes the URL substitution process.

To ensure this refactor doesn't introduce any regressions, please run the following test script:

This script will help verify that the refactored function handles various URL patterns correctly, including cases with missing environment variables.

lua/hurl/utils.lua Outdated Show resolved Hide resolved
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
lua/hurl/utils.lua (1)

340-340: Remove unnecessary comment about url parameter

The comment -- Assuming \url` is defined earlier in the codeis unnecessary sinceurlis a parameter of the functionutil.convert_url_to_proper_format`. Removing this comment will improve code clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d4dffb6 and f817207.

📒 Files selected for processing (1)
  • lua/hurl/utils.lua (1 hunks)
🧰 Additional context used

local key, value = line:match('^(%S+)%s*=%s*(.+)$') -- Match key=value
if key and value then
-- Trim quotes from value, if present
value = value:gsub('^"%s*', ''):gsub('"%s*$', ''):gsub("^'%s*", ''):gsub("'%s*$", '')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify and correct the quote trimming logic

The current code for trimming quotes from the value variable can be simplified and made more robust. Consider using patterns that remove both single and double quotes from the start and end of the string, including any surrounding whitespace.

Apply this diff to improve the quote trimming:

- value = value:gsub('^"%s*', ''):gsub('"%s*$', ''):gsub("^'%s*", ''):gsub("'%s*$", '')
+ value = value:gsub("^%s*['\"]?", ''):gsub("['\"]?%s*$", '')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
value = value:gsub('^"%s*', ''):gsub('"%s*$', ''):gsub("^'%s*", ''):gsub("'%s*$", '')
value = value:gsub("^%s*['\"]?", ''):gsub("['\"]?%s*$", '')

Comment on lines +374 to +378
for key, value in pairs(env_vars) do
if url:find('{{' .. key .. '}}') then
url = url:gsub('{{' .. key .. '}}', value)
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle unresolved placeholders in URL

If the URL contains placeholders that are not found in the environment variables, the placeholders will remain in the URL, which may cause issues in downstream processing. Consider adding a check for unresolved placeholders and logging a warning if any are found.

Apply this diff to handle unresolved placeholders:

       end
     end

+    -- After replacements, check for unresolved placeholders
+    if url:find('{{.-}}') then
+      util.log_error('Unresolved placeholders remain in URL: ' .. url)
+    end
   else
     util.log_error('No environment file found in opts.')
   end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for key, value in pairs(env_vars) do
if url:find('{{' .. key .. '}}') then
url = url:gsub('{{' .. key .. '}}', value)
end
end
for key, value in pairs(env_vars) do
if url:find('{{' .. key .. '}}') then
url = url:gsub('{{' .. key .. '}}', value)
end
end
-- After replacements, check for unresolved placeholders
if url:find('{{.-}}') then
util.log_error('Unresolved placeholders remain in URL: ' .. url)
end

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f817207 and 0118867.

📒 Files selected for processing (1)
  • lua/hurl/main.lua (4 hunks)
🧰 Additional context used

@@ -126,11 +126,15 @@ local on_output = function(code, data, event)
end
end

local last_request_opts = nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add documentation and improve request storage logic.

The implementation of last request storage could be improved:

  1. Add LuaDoc comments to document the last_request_opts variable
  2. Move the assignment after the running check to avoid storing failed requests
  3. Consider adding a cleanup mechanism for the stored request
--- Variable declaration
+--- @type table|nil
+--- @field opts table The options for the last successful request
 local last_request_opts = nil

 local function execute_hurl_cmd(opts, callback)
   if is_running then
     utils.log_info('hurl: request is already running')
     utils.notify('hurl: request is running. Please try again later.', vim.log.levels.INFO)
     return
   end
+  last_request_opts = opts
-  last_request_opts = opts

Also applies to: 135-136

Comment on lines +598 to +607
utils.create_cmd('HurlRerun', function()
if last_request_opts then
run_lines(last_request_opts, {})
else
utils.log_info('No last request to re-run')
end
end, {
nargs = '*',
range = true,
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance rerun functionality with validation and feedback.

The rerun implementation could be improved:

  1. Add type checking for last_request_opts
  2. Validate stored request data
  3. Add user feedback for successful rerun
 utils.create_cmd('HurlRerun', function()
   if last_request_opts then
+    if type(last_request_opts) ~= 'table' then
+      utils.notify('Invalid last request data', vim.log.levels.ERROR)
+      return
+    end
+    if vim.tbl_isempty(last_request_opts) then
+      utils.notify('Empty last request data', vim.log.levels.ERROR)
+      return
+    end
     run_lines(last_request_opts, {})
+    utils.notify('Rerunning last request...', vim.log.levels.INFO)
   else
-    utils.log_info('No last request to re-run')
+    utils.notify('No last request to re-run', vim.log.levels.WARN)
   end
 end, {
   nargs = '*',
   range = true,
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
utils.create_cmd('HurlRerun', function()
if last_request_opts then
run_lines(last_request_opts, {})
else
utils.log_info('No last request to re-run')
end
end, {
nargs = '*',
range = true,
})
utils.create_cmd('HurlRerun', function()
if last_request_opts then
if type(last_request_opts) ~= 'table' then
utils.notify('Invalid last request data', vim.log.levels.ERROR)
return
end
if vim.tbl_isempty(last_request_opts) then
utils.notify('Empty last request data', vim.log.levels.ERROR)
return
end
run_lines(last_request_opts, {})
utils.notify('Rerunning last request...', vim.log.levels.INFO)
else
utils.notify('No last request to re-run', vim.log.levels.WARN)
end
end, {
nargs = '*',
range = true,
})

Comment on lines +207 to +214
if _HURL_GLOBAL_CONFIG.url.show then
local url = utils.get_url_from_hurl_file(opts[1])
if _HURL_GLOBAL_CONFIG.url.format_without_params then
url = utils.convert_url_to_proper_format(opts, url)
end
response.url = url
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling and validation for URL display.

The URL display implementation could be improved:

  1. Add error handling for URL extraction failures
  2. Validate the URL format
  3. Document the URL configuration options
 if _HURL_GLOBAL_CONFIG.url.show then
-  local url = utils.get_url_from_hurl_file(opts[1])
+  local url, err = utils.get_url_from_hurl_file(opts[1])
+  if err then
+    utils.log_warn('hurl: failed to extract URL: ' .. err)
+    return
+  end
+  if not url:match('^https?://') then
+    utils.log_warn('hurl: invalid URL format: ' .. url)
+    return
+  end
   if _HURL_GLOBAL_CONFIG.url.format_without_params then
     url = utils.convert_url_to_proper_format(opts, url)
   end
   response.url = url
 end

Committable suggestion was skipped due to low confidence.

@jellydn
Copy link
Owner

jellydn commented Oct 27, 2024

Closed by #207

@jellydn jellydn closed this Oct 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants