diff --git a/src/github_api.cr b/src/github_api.cr index 69979ac..75a78a5 100644 --- a/src/github_api.cr +++ b/src/github_api.cr @@ -289,12 +289,33 @@ struct Artifact repo_owner = repo_owner.downcase repo_name = repo_name.downcase @@cache_zip_by_id.fetch({repo_owner, repo_name, artifact_id}, expires_in: 50.seconds) do - # https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#download-an-artifact + # https://docs.github.com/en/rest/reference/actions#download-an-artifact resp = GitHub.get( "repos/#{repo_owner}/#{repo_name}/actions/artifacts/#{artifact_id}/zip", headers: {Authorization: token} ) - if resp.status_code == 500 && resp.body.includes?("Failed to generate URL to download artifact") + if resp.status_code == 410 || (resp.status_code == 500 && resp.body.includes?("Failed to generate URL to download artifact")) + raise GitHubArtifactDownloadError.new(status_code: resp.status_code, uri: resp.uri) + end + resp.raise_for_status + resp.headers["location"] + end + end +end + +struct Logs + @@cache_raw_by_id = CleanedMemoryCache({String, String, Int64}, String).new + + def self.raw_by_id(repo_owner : String, repo_name : String, job_id : Int64, token : InstallationToken | UserToken) : String + repo_owner = repo_owner.downcase + repo_name = repo_name.downcase + @@cache_raw_by_id.fetch({repo_owner, repo_name, job_id}, expires_in: 50.seconds) do + # https://docs.github.com/en/rest/reference/actions#download-job-logs-for-a-workflow-run + resp = GitHub.get( + "repos/#{repo_owner}/#{repo_name}/actions/jobs/#{job_id}/logs", + headers: {Authorization: token} + ) + if resp.status_code == 410 raise GitHubArtifactDownloadError.new(status_code: resp.status_code, uri: resp.uri) end resp.raise_for_status diff --git a/src/nightly_link.cr b/src/nightly_link.cr index 299eca8..2149966 100644 --- a/src/nightly_link.cr +++ b/src/nightly_link.cr @@ -122,6 +122,10 @@ record RepoInstallation, end end +private def github_job_link(repo_owner : String, repo_name : String, job_id : Int64) : String + "https://github.com/#{repo_owner}/#{repo_name}/runs/#{job_id}" +end + private def github_run_link(repo_owner : String, repo_name : String, run_id : Int64) : String "https://github.com/#{repo_owner}/#{repo_name}/actions/runs/#{run_id}#artifacts" end @@ -442,6 +446,31 @@ class NightlyLink end end + @[Retour::Get("/{repo_owner}/{repo_name}/commit/{commit:[0-9a-fA-F]{40}}/checks/{job_id:[0-9]+}/logs")] + def logs_by_job(ctx, repo_owner : String, repo_name : String, commit : String?, job_id : String | Int64, h : String? = nil) + job_id = job_id.to_i64 rescue raise HTTPException.new(:NotFound) + h = ctx.request.query_params["h"]? if ctx + token, h = RepoInstallation.verified_token(@db, repo_owner, repo_name, h: h) + + gh_link = github_job_link(repo_owner, repo_name, job_id) + tmp_link = begin + Logs.raw_by_id(repo_owner, repo_name, job_id, token: token) + rescue e : GitHubArtifactDownloadError + raise HTTPException.new(:NotFound, + "It seems that the logs for job ##{job_id} have expired.\n" + + "Check on GitHub: <#{gh_link}>" + ) + rescue e : Halite::Exception::ClientError + if e.status_code.in?(401, 404) + raise HTTPException.new(:NotFound, + "Job ##{job_id} not found.\nCheck on GitHub: <#{gh_link}>" + ) + end + raise e + end + raise HTTPException.redirect(tmp_link) + end + {% for path, i in ["github-markdown.min.css", "logo.svg"] %} {% ext = path.split(".")[-1] %} {% headers = "#{ext.upcase.id}_HEADERS".id %}