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

feat: poc octo run list #638

Open
wants to merge 56 commits into
base: master
Choose a base branch
from

Conversation

GustavEikaas
Copy link

@GustavEikaas GustavEikaas commented Oct 15, 2024

Important

This is a draft PR
Im making this draft PR so I can get reviews/suggestions during development
I will fill out the PR template when the PR is ready for review

Resolves: #149

Describe what this PR does / why we need it

First PR in a series of PRs to add support for github actions

Does this pull request fix one issue?

Describe how you did it

Describe how to verify it

Special notes for reviews

Checklist

  • Passing tests and linting standards
  • Documentation updates in README.md and doc/octo.txt

Feature checklist

  • Buffer
    • Expand/collapse node
    • Highlights
    • Keybindings
      • Refresh
  • Workflows
    • Support multiple jobs
  • Workflow job steps
    • Logs
    • Status
    • ##[group]
    • [command]

Remaining

  • Customizable keymappings
  • Customizable icons
  • Update readme
  • Cleanup code
  • Customizable refresh interval
  • Look into using graphql in favor of gh cli commands (not sure if strictly necessary but conforms to the repo standard)
  • Use telescope pickers from the repo
  • Understand the writers.lua file and extend it
  • Use existing octo window creator

@wd60622
Copy link
Collaborator

wd60622 commented Oct 17, 2024

Using graphql is not a big deal. Just use whatever endpoint that works. Think there are a few non graphql commands used.

@GustavEikaas
Copy link
Author

Ah okay, functionality wise, do you have any feedback?

@wd60622
Copy link
Collaborator

wd60622 commented Oct 17, 2024

Ah okay, functionality wise, do you have any feedback?

I will give it a try when I can!

@wd60622 wd60622 added the enhancement New feature or request label Oct 17, 2024
@wd60622
Copy link
Collaborator

wd60622 commented Oct 18, 2024

Think it looks good. Would you want to make use of the pickers instead of the new, custom buffer? I have been using telescope recently. What do you use?

Some items:

  • What do you expect the callback to be upon selection an item? We can work something in like Abitrary callbacks for pickers #642 in order to support more in the future.
  • Would there be a preview or buffer to show each item? What would be populated there? Maybe a buffer doesn't make sense here. What are your thoughts?

@GustavEikaas
Copy link
Author

image
@wd60622 Is this what you meant, kinda like the PR and issue flow?

@GustavEikaas
Copy link
Author

You still want there to be a buffer when you press <CR> on one of the items in the picker. AKA same flow as pull request?

@pwntester
Copy link
Owner

Thanks for the PR @GustavEikaas!

I like the idea of showing the status of the run in the preview buffer and perhaps show the logs of the run upon opening the item with <CR>. The problem I see is that a run may contain multiple jobs and each job will have its own log. Should we present them sequentially? thoughts?

@GustavEikaas
Copy link
Author

IIRC the sequential jobs is already supported but yes I was thinking the same.
For the logs of every step we should probably lazy load and use fold or something similiar. Some steps have very long log outputs

@GustavEikaas
Copy link
Author

@pwntester
Here is an image of what it looks like with multiple jobs
image

@GustavEikaas
Copy link
Author

Doesnt seem like there is a good structured output for workflow logs. Will probably be tricky to have the same UI as github web.
Only way I see right now is query the workflow logs and using regex to match the lines to the corresponding steps

@pwntester
Copy link
Owner

Nice, perhaps we can do a nested telescope selection where the use first chooses the run and then the job, that should get us a shorter log to show to the user and it should easier to print since we dont need to care about job's dependencies, just sequential steps

@GustavEikaas
Copy link
Author

Finally found it. Its a POSIX quirk. From the lua docs for os.tmpname

In POSIX systems, this function also creates a file with that name, to avoid security risks. (Someone else might create the file with wrong permissions in the time between getting the name and creating the file.) You still have to open the file to use it and to remove it (even if you do not use it).

@GustavEikaas
Copy link
Author

GustavEikaas commented Jan 16, 2025

Latest commit works fine on arch (btw), and windows. Should work just fine for you now @wd60622.
What weird behaviour for os.tmpname....

@wd60622
Copy link
Collaborator

wd60622 commented Jan 16, 2025

Thanks for the updates. will give it a try when I can

@wd60622
Copy link
Collaborator

wd60622 commented Jan 25, 2025

Okay. I am able to get it to work (for a few) now. I am still getting this traceback:

E5108: Error executing lua: Vim:E484: Can't open file vpavbvq/X64-ubuntu (ubuntu-20.04, https:/github.com/neovim/neovim/releases/download/v0.7.0/n
vim-linux64..../1_Set up job.txt
stack traceback:
        [C]: in function 'readfile'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:341: in function 'cb'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:208: in function 'traverse'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:210: in function 'traverse'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:210: in function 'traverse'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:333: in function 'get_logs'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:390: in function 'cb'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:611: in function <...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:
607>

Maybe there is something with the filename then.

Overall it looks really awesome @GustavEikaas. Thanks for the final push here!

@GustavEikaas
Copy link
Author

Yeah ill take a last look at escaping/normalizing filenames

@wd60622
Copy link
Collaborator

wd60622 commented Jan 25, 2025

Yeah ill take a last look at escaping/normalizing filenames

Great. Thank you!

@wd60622
Copy link
Collaborator

wd60622 commented Jan 25, 2025

I am also noticing that the folders are being created off of my cwd. Is that as expected?

@GustavEikaas
Copy link
Author

Good catch ill fix that, happened after i migrated away from os.tmpname.

@GustavEikaas
Copy link
Author

GustavEikaas commented Jan 25, 2025

Okay. I am able to get it to work (for a few) now. I am still getting this traceback:

Im not sure if I fixed the same issue you were facing but for me it would fail if it tried to read the logs of a step that was skipped. This was because the .txt file is missing from the zip archive. I added a check so that skipped steps are not assigned logs.

I am also noticing that the folders are being created off of my cwd. Is that as expected?

Fixed.

Encountered a strange scenario I have never seen before. In a workflow from Neovim repo it failed to load because workflow.jobs == nil. After opening it in browser this is what I see.
image
Given the data available to me this is the best I can do. Clearly the gh api is not as powerful as the web UI. But it will hopefully improve over time.
image

@GustavEikaas
Copy link
Author

Still a couple of rough edges in this PR but I think its getting ready to merge. Given that it stops giving you errors

For any future issues/prs/discussions feel free to tag me, I would like to keep working on this

@wd60622
Copy link
Collaborator

wd60622 commented Jan 25, 2025

I'm having a lot better luck with it now. Really cool feature.

I am running into this:

                                                                                                                                1,15          All
E5108: Error executing lua: ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:597: 'replacement string' item contains newlines
stack traceback:
        [C]: in function 'nvim_buf_set_lines'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:597: in function 'print_lines'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:623: in function 'refresh'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:525: in function 'populate_preview_buffer'
        ...tHub/neovim-plugins/octo.nvim/lua/octo/workflow_runs.lua:680: in function 'define_preview'
        ...scope.nvim/lua/telescope/previewers/buffer_previewer.lua:451: in function 'preview'
        ...share/nvim/lazy/telescope.nvim/lua/telescope/pickers.lua:1212: in function 'refresh_previewer'
        ...share/nvim/lazy/telescope.nvim/lua/telescope/pickers.lua:1153: in function 'set_selection'
        ...share/nvim/lazy/telescope.nvim/lua/telescope/pickers.lua:912: in function 'move_selection'
        ...e/nvim/lazy/telescope.nvim/lua/telescope/actions/set.lua:39: in function 'run_replace_or_original'
        ...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:65: in function 'shift_selection'
        .../nvim/lazy/telescope.nvim/lua/telescope/actions/init.lua:87: in function 'run_replace_or_original'
        ...re/nvim/lazy/telescope.nvim/lua/telescope/actions/mt.lua:65: in function 'key_func'
        ...hare/nvim/lazy/telescope.nvim/lua/telescope/mappings.lua:293: in function <...hare/nvim/lazy/telescope.nvim/lua/telescope/mappings.lua:
292>

Also, could you bind to the buffer to get the URL of the run? Think that could be pretty convenient. Or at least in the picker if it isn't already!

@GustavEikaas
Copy link
Author

GustavEikaas commented Jan 25, 2025

I did bind <C-b> open in browser for the buffer. I can do <C-y> aswell.

Are you testing against open repositories, can you link a workflow run that fails? Seems like it complains about \n in a line being printed. Not really sure why that would happen, weird... Did it happen when printing the workflow or when getting the workflow step logs?

@GustavEikaas
Copy link
Author

GustavEikaas commented Jan 26, 2025

I managed to repro your issue @wd60622 and I might have found a bug in github...
when downloading the archive from workflow
I get this. But when trying to cd into the directory I get this error
image
image
image

Not really sure how to proceed here. Will make an issue with github to gather some more info. I enabled longpaths on my windows system and still not working

EDIT: Did some more digging and it seems like unzip is the reason it fails. When unzipping the folder with the long path name it just corrupts... Will do more digging

EDIT2
Finally got it working but jesus there are a lot of inconsistencies in github apis. When querying the workflow I get different characters than when querying wf logs. It aint great but its working. I also couldnt unzip the archive with unzip without corrupting the directory?? Ended up rewriting the logic to extract single files into stdout per workflow step

    local sanitized_name = node.id:gsub("/", ""):gsub(":", ""):gsub(">","")
    --Make more than 3 consecutive dots at the end of line into ...
    local sanitized_job_id = node.job_id:gsub("/", ""):gsub(":", ""):gsub("%.%.%.%.+$", "...")

@wd60622
Copy link
Collaborator

wd60622 commented Jan 29, 2025

Was still having issues with this. Does it have something to do with the file / folder names. Should we use a hash or something?

@GustavEikaas
Copy link
Author

Darn, really?

Well the problem is I do api calls to get the workflow and based on the dynamic info there I request an archive with an arbitary number of files with names that can be built up using the workflow but with x amount of replaced characters. Ill do some more digging

@wd60622
Copy link
Collaborator

wd60622 commented Feb 2, 2025

Thanks for all of the digging. Feel free to ping me to try again.

Maybe @GuillaumeLagrange can try as well!

@GustavEikaas
Copy link
Author

Ill keep digging! It would be easier if anyone could link me a specific workflow run that causes it to error out

M.refresh()
return
end
local cmd = string.format("gh run view %s --json %s", id, fields)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Possible to use existing code here?

Might look like this:

gh = require "octo.gh"

gh.run.view {
  id,
  json=fields, 
  opts = {
    cb = function(output, stderr)
    end,
  }
}

Copy link
Author

@GustavEikaas GustavEikaas Feb 20, 2025

Choose a reason for hiding this comment

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

You mean like this?
Or did you want me to create the gh.run.view?

  gh.run {
    args = { "run", "view", id, "--json", fields },
    cb = function(output, stderr)
      if stderr and not utils.is_blank(stderr) then
        vim.api.nvim_err_writeln(stderr)
        octo_error("Failed to get workflow run for " .. id)
      elseif output then
        job_details = vim.fn.json_decode(output)
        M.wf_cache[id] = job_details
        M.current_wf = job_details
        M.tree = generate_workflow_tree(job_details)
        M.refresh()
      end
    end,
  }

Copy link
Collaborator

Choose a reason for hiding this comment

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

Arbitrary CLI commands are already supported with this logic:

local create_subcommand = function(command)
local subcommand = {}
subcommand.command = command
setmetatable(subcommand, {
__index = function(t, key)
return function(opts)
opts = opts or {}
local run_opts = opts.opts or {}
local args = {
t.command,
key,
}
opts.opts = nil
args = M.insert_args(args, opts, { ["_"] = "-" })
return M.run {
args = args,
mode = run_opts.mode,
cb = run_opts.cb,
stream_cb = run_opts.stream_cb,
headers = run_opts.headers,
hostname = run_opts.hostname,
}
end
end,
})
return subcommand
end
setmetatable(M, {
__index = function(_, key)
return create_subcommand(key)
end,
})

So no need to write it. Just use what I wrote and fill in the callback

Copy link
Collaborator

@wd60622 wd60622 left a comment

Choose a reason for hiding this comment

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

Some comments.

Also, been thinking about the use of zip files (Still don't have working in all cases for me)...
Do the logs have to stored to file system? There are other items that are just stored in the local variable M. Can that strategy also be used?

end

M.list = function()
vim.notify "Fetching workflow runs (this may take a while) ..."
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use utils.info over vim.notify

local co = coroutine.running()
local wf_runs = get_workflow_runs_sync(co)

require("octo.pickers.telescope.provider").workflow_runs(wf_runs, "Workflow runs", render)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use require "octo.picker" instead. Feel free to have M.not_implemented for the other two pickers

local function get_workflow_runs_sync(co)
local lines = {}
vim.fn.jobstart(
"gh run list --json conclusion,displayTitle,event,headBranch,name,number,status,updatedAt,databaseId -L "
Copy link
Collaborator

Choose a reason for hiding this comment

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

Possible to use gh.run / gh.run.list here as well?
Using that ensures that the environment variables are correct

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request - GitHub actions
3 participants