From 116e8f05621a9793e4b4beda50430d8624ca6c06 Mon Sep 17 00:00:00 2001
From: Oleh Prypin
Date: Sat, 13 Feb 2021 18:05:06 +0100
Subject: [PATCH] If there is 1 artifact, don't require clicking through to it
---
spec/main_spec.cr | 61 +++++++++++++++++++++++------------------
src/nightly_link.cr | 4 +++
templates/controls.html | 3 +-
3 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/spec/main_spec.cr b/spec/main_spec.cr
index ac17fb4..53c8f50 100644
--- a/spec/main_spec.cr
+++ b/spec/main_spec.cr
@@ -15,6 +15,7 @@ RUN_3 = 987654326
JOB_1 = 9977553311
JOB_2 = 9977553317
ARTIFACT_1 = 87654321
+ARTIFACT_2 = 87654325
PRIVATE_REPO = "oprypin/test-private-repo"
require "http"
@@ -156,7 +157,9 @@ describe "dash_by_branch" do
body: %({"workflow_runs":[
{"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/UserName/RepoName/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"UserName/RepoName","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/runs/#{RUN_2}/artifacts?per_page=100").to_return(
- body: %({"artifacts":[{"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_1}"}]}))
+ body: %({"artifacts":[
+ {"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_1}"},
+ {"id":#{ARTIFACT_2},"name":"AnotherArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_2}"}]}))
end
test do
@@ -194,12 +197,14 @@ describe "dash_by_branch" do
test do
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/workflows/SomeWorkflow.yml/runs?per_page=1&branch=SomeBranch&event=push&status=success").to_return(
body: %({"workflow_runs":[
- {"id":#{RUN_1},"event":"push","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2020-12-19T22:22:22Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
+ {"id":#{RUN_1},"event":"push","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2020-12-19T22:22:22Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/workflows/SomeWorkflow.yml/runs?per_page=1&branch=SomeBranch&event=schedule&status=success").to_return(
body: %({"workflow_runs":[
- {"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
+ {"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/runs/#{RUN_2}/artifacts?per_page=100").to_return(
- body: %({"artifacts":[{"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_1}"}]}))
+ body: %({"artifacts":[
+ {"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_1}"},
+ {"id":#{ARTIFACT_2},"name":"AnotherArtifact","url":"https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_2}"}]}))
resp, body = serve("/#{PRIVATE_REPO}/workflows/SomeWorkflow/SomeBranch?h=6c9bf24563d1896f5de321ce6043413f8c75ef16")
assert_canonical "https://nightly.link/#{PRIVATE_REPO}/workflows/SomeWorkflow/SomeBranch?h=6c9bf24563d1896f5de321ce6043413f8c75ef16"
@@ -248,11 +253,11 @@ describe "dash_by_run" do
resp, body = serve("/uSerName/RepoName/actions/runs/#{RUN_1}")
assert_canonical "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_1}"
assert_contents [
- "Repository UserName/RepoName", "Run #987654321",
- "Repository UserName/RepoName", "Run #987654321",
- "https://nightly.link/UserName/RepoName/actions/runs/987654321/SomeArtifact",
- "https://nightly.link/UserName/RepoName/actions/runs/987654321/SomeArtifact.zip",
- "https://nightly.link/UserName/RepoName/actions/runs/987654321/SomeArtifact.zip",
+ "Repository UserName/RepoName", "Run ##{RUN_1}",
+ "Repository UserName/RepoName", "Run ##{RUN_1}",
+ "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact",
+ "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact.zip",
+ "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact.zip",
]
assert_nofollow
end
@@ -264,8 +269,8 @@ describe "dash_by_run" do
resp, body = serve("/UserName/RepoName/actions/runs/#{RUN_3}")
assert resp.status == HTTP::Status::NOT_FOUND
assert_contents [
- "No artifacts found for run #987654326",
- "https://github.com/UserName/RepoName/actions/runs/987654326#artifacts",
+ "No artifacts found for run ##{RUN_3}",
+ "https://github.com/UserName/RepoName/actions/runs/#{RUN_3}#artifacts",
]
assert_nofollow
end
@@ -275,12 +280,14 @@ describe "by_branch" do
before_each do
WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/workflows/SomeWorkflow.yml/runs?per_page=1&branch=SomeBranch&event=push&status=success").to_return(
body: %({"workflow_runs":[
- {"id":#{RUN_1},"event":"push","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/UserName/RepoName/check-suites/#{CHECK_SUITE_1}","updated_at":"2020-12-19T22:22:22Z","repository":{"full_name":"UserName/RepoName","private":false,"fork":false}}]}))
+ {"id":#{RUN_1},"event":"push","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/UserName/RepoName/check-suites/#{CHECK_SUITE_1}","updated_at":"2020-12-19T22:22:22Z","repository":{"full_name":"UserName/RepoName","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/workflows/SomeWorkflow.yml/runs?per_page=1&branch=SomeBranch&event=schedule&status=success").to_return(
body: %({"workflow_runs":[
- {"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/UserName/RepoName/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"UserName/RepoName","private":false,"fork":false}}]}))
+ {"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/UserName/RepoName/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"UserName/RepoName","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/runs/#{RUN_2}/artifacts?per_page=100").to_return(
- body: %({"artifacts":[{"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_1}"}]}))
+ body: %({"artifacts":[
+ {"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_1}"},
+ {"id":#{ARTIFACT_2},"name":"AnotherArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_2}"}]}))
WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/artifacts/#{ARTIFACT_1}/zip").to_return(
headers: HTTP::Headers{"location" => "http://example.org/download1"})
end
@@ -330,12 +337,14 @@ describe "by_branch" do
test do
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/workflows/SomeWorkflow.yml/runs?per_page=1&branch=SomeBranch&event=push&status=success").to_return(
body: %({"workflow_runs":[
- {"id":#{RUN_1},"event":"push","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2020-12-19T22:22:22Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
+ {"id":#{RUN_1},"event":"push","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2020-12-19T22:22:22Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/workflows/SomeWorkflow.yml/runs?per_page=1&branch=SomeBranch&event=schedule&status=success").to_return(
body: %({"workflow_runs":[
- {"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
+ {"id":#{RUN_2},"event":"schedule","workflow_id":#{WORKFLOW_1},"check_suite_url":"https://api.github.com/repos/#{PRIVATE_REPO}/check-suites/#{CHECK_SUITE_1}","updated_at":"2021-02-07T07:15:00Z","repository":{"full_name":"#{PRIVATE_REPO}","private":false,"fork":false}}]}))
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/runs/#{RUN_2}/artifacts?per_page=100").to_return(
- body: %({"artifacts":[{"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_1}"}]}))
+ body: %({"artifacts":[
+ {"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_1}"},
+ {"id":#{ARTIFACT_2},"name":"AnotherArtifact","url":"https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_2}"}]}))
WebMock.stub(:get, "https://api.github.com/repos/#{PRIVATE_REPO}/actions/artifacts/#{ARTIFACT_1}/zip").to_return(
headers: HTTP::Headers{"location" => "http://example.org/download2"})
@@ -358,29 +367,29 @@ end
describe "by_run" do
before_each do
- WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/runs/#{RUN_2}/artifacts?per_page=100").to_return(
+ WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/runs/#{RUN_1}/artifacts?per_page=100").to_return(
body: %({"artifacts":[{"id":#{ARTIFACT_1},"name":"SomeArtifact","url":"https://api.github.com/repos/UserName/RepoName/actions/artifacts/#{ARTIFACT_1}"}]}))
WebMock.stub(:get, "https://api.github.com/repos/username/reponame/actions/artifacts/#{ARTIFACT_1}/zip").to_return(
headers: HTTP::Headers{"location" => "http://example.org/download1"})
end
test do
- resp, body = serve("/UserName/RepoName/actions/runs/#{RUN_2}/SomeArtifact")
- assert_canonical "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_2}/SomeArtifact"
+ resp, body = serve("/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact")
+ assert_canonical "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact"
assert_contents [
- "Repository UserName/RepoName", "Run #987654324 | Artifact SomeArtifact",
+ "Repository UserName/RepoName", "Run ##{RUN_1} | Artifact SomeArtifact",
] * 2 + [
- "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_2}/SomeArtifact.zip",
+ "https://nightly.link/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact.zip",
"https://nightly.link/UserName/RepoName/actions/artifacts/#{ARTIFACT_1}.zip",
].flat_map { |s| [s, s] } + [
"http://example.org/download1",
- "https://github.com/UserName/RepoName/actions/runs/#{RUN_2}#artifacts",
+ "https://github.com/UserName/RepoName/actions/runs/#{RUN_1}#artifacts",
]
assert_nofollow
end
test "redirect" do
- resp, body = serve("/UserName/RepoName/actions/runs/#{RUN_2}/SomeArtifact.zip")
+ resp, body = serve("/UserName/RepoName/actions/runs/#{RUN_1}/SomeArtifact.zip")
assert_redirect "http://example.org/download1"
end
end
@@ -425,8 +434,8 @@ describe "by_job" do
resp, body = serve("/uSerName/RepoName/runs/#{JOB_1}")
assert_canonical "https://nightly.link/uSerName/RepoName/runs/#{JOB_1}"
assert_contents [
- "Repository uSerName/RepoName", "Job #9977553311",
- "Repository uSerName/RepoName", "Job #9977553311",
+ "Repository uSerName/RepoName", "Job ##{JOB_1}",
+ "Repository uSerName/RepoName", "Job ##{JOB_1}",
"https://nightly.link/uSerName/RepoName/runs/#{JOB_1}.txt",
"http://example.org/download1",
"https://github.com/uSerName/RepoName/runs/#{JOB_1}",
diff --git a/src/nightly_link.cr b/src/nightly_link.cr
index 71127e0..5912d6c 100644
--- a/src/nightly_link.cr
+++ b/src/nightly_link.cr
@@ -333,6 +333,10 @@ class NightlyLink
repo_owner: repo_owner, repo_name: repo_name, workflow: workflow.rchop(".yml"), branch: branch, artifact: art.name
)), art.name, h: h)
end
+ if links.size == 1
+ raise HTTPException.redirect(links[0].url)
+ end
+
title = {"Repository #{repo_owner}/#{repo_name}", "Workflow #{workflow} | Branch #{branch}"}
canonical = abs_url(NightlyLink.gen_dash_by_branch(
repo_owner: repo_owner, repo_name: repo_name, workflow: workflow.rchop(".yml"), branch: branch
diff --git a/templates/controls.html b/templates/controls.html
index 405141c..d964f37 100644
--- a/templates/controls.html
+++ b/templates/controls.html
@@ -25,7 +25,8 @@ Paste a GitHub link, get a nightly.link!
Link to a repository's latest artifact
Insert the GitHub URL of a workflow file that uses actions/upload-artifact.
-Example: <%= HTML.escape(example_workflow) %>
+Example: <%= HTML.escape(example_workflow) %>
+Note that the branch which you're on also matters.
Following this form (and having selected the "<%= example_art %>" artifact), you will end up at
<%= example_dest %> [.zip]
which is a link that always downloads the latest artifact from a succeeding run on that repo+workflow+branch.
If you have several workflows or branches, you can adapt the URL by hand in a predictable way.