Add CI/CD tab and pipeline summary page to repository UI

Seto Elkahfi committed Apr 15, 2026 at 22:38 UTC 9e42334b54ba445c5186c626633b06b5ebfe6793
9 files changed +306 -6
app/controllers/blobs_controller.rb
+1
index dab4fc8..f987d88 100644 --- a/app/controllers/blobs_controller.rb +++ b/app/controllers/blobs_controller.rb @@ -17,6 +17,7 @@ class BlobsController < ApplicationController @raw_content = content @filename = File.basename(@file_path) @extension = File.extname(@filename).delete_prefix(".") + @commit_count = GitRepositoryService.commit_count(@repository.disk_path, @branch) @is_binary = content.encoding != Encoding::UTF_8 || !content.valid_encoding? || binary_content?(content) @file_size = content.bytesize
app/controllers/commits_controller.rb
+1
index e3e80fc..509b43e 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -19,6 +19,7 @@ class CommitsController < ApplicationController limit: @per_page, offset: @offset ) @total = GitRepositoryService.commit_count(@repository.disk_path, @branch) + @commit_count = @total @total_pages = (@total.to_f / @per_page).ceil end
app/controllers/repositories_controller.rb
+36 -3
index 21538be..3f31efa 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -1,8 +1,8 @@ class RepositoriesController < ApplicationController before_action :require_sign_in!, only: [ :new, :create ] - before_action :load_owner, only: [ :show, :tree ] - before_action :load_repository, only: [ :show, :tree ] - before_action :ensure_can_read!, only: [ :show, :tree ] + before_action :load_owner, only: [ :show, :tree, :cicd ] + before_action :load_repository, only: [ :show, :tree, :cicd ] + before_action :ensure_can_read!, only: [ :show, :tree, :cicd ] def new @repository = Repository.new @@ -64,6 +64,7 @@ class RepositoriesController < ApplicationController @tree = GitRepositoryService.list_tree(@repository.disk_path, branch, tree_path) @current_path = tree_path @path_parts = tree_path.to_s.split("/").reject(&:blank?) + @commit_count = GitRepositoryService.commit_count(@repository.disk_path, branch) # If it's actually a file, redirect to the blob view if @tree.empty? @@ -71,6 +72,38 @@ class RepositoriesController < ApplicationController end end + def cicd + @branch = @repository.default_branch + @commit_count = if @repository.initialized? && GitRepositoryService.branch_exists?(@repository.disk_path, @branch) + GitRepositoryService.commit_count(@repository.disk_path, @branch) + else + 0 + end + @pipeline_summary = { + success_rate: "98.4%", + avg_duration: "6m 12s", + weekly_runs: 27, + last_deploy: "18 minutes ago" + } + @pipeline_runs = [ + { name: "Deploy production", ref: "main", sha: "8f3c1b2", status: "passed", duration: "5m 48s", started_at: "18 minutes ago", actor: "sigit" }, + { name: "PR validation", ref: "feature/repo-tabs", sha: "7bd91aa", status: "running", duration: "2m 14s", started_at: "now", actor: "naufal" }, + { name: "Nightly security scan", ref: "main", sha: "4c72e16", status: "passed", duration: "9m 03s", started_at: "7 hours ago", actor: "automation" }, + { name: "Deploy staging", ref: "release/apr", sha: "cb194ef", status: "failed", duration: "4m 51s", started_at: "yesterday", actor: "sigit" } + ] + @environments = [ + { name: "Production", url: "app.sigitsi.com", status: "healthy", version: "v1.24.0", updated_at: "18 minutes ago" }, + { name: "Staging", url: "staging.sigitsi.com", status: "degraded", version: "v1.25.0-rc.2", updated_at: "42 minutes ago" }, + { name: "Preview", url: "preview-482.sigitsi.com", status: "building", version: "feature/repo-tabs", updated_at: "2 minutes ago" } + ] + @checks = [ + { name: "RSpec", status: "passed", detail: "248 examples in 32s" }, + { name: "Brakeman", status: "passed", detail: "0 warnings" }, + { name: "Lint", status: "running", detail: "RuboCop on 84 files" }, + { name: "Deploy smoke test", status: "failed", detail: "Health endpoint timed out once" } + ] + end + private def repository_params
app/views/blobs/show.html.erb
+23 -1
index 55921e8..c449572 100644 --- a/app/views/blobs/show.html.erb +++ b/app/views/blobs/show.html.erb @@ -18,7 +18,29 @@ <span class="font-medium text-gray-100"><%= @filename %></span> </nav> <div class="flex items-center gap-0 -mb-px"> - <div class="tab-item active">Code</div> + <%= link_to repository_path(@owner.username, @repository.name), class: "tab-item active flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/> + </svg> + Code + <% end %> + <%= link_to repository_commits_path(@owner.username, @repository.name, @branch), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/> + </svg> + Commits + <% end %> + <%= link_to repository_cicd_path(@owner.username, @repository.name), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/> + </svg> + CI/CD + <% if @commit_count&.> 0 %> + <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> + <% end %> + <% end %> </div> </div> </div>
app/views/commits/index.html.erb
+32 -2
index 19e3e60..b89b98e 100644 --- a/app/views/commits/index.html.erb +++ b/app/views/commits/index.html.erb @@ -3,16 +3,46 @@ <div class="border-b border-surface-600 bg-surface-800"> <div class="max-w-6xl mx-auto px-4 sm:px-6 pt-6 pb-0"> <div class="flex items-center gap-2 text-sm mb-4"> + <svg class="w-4 h-4 text-gray-500" viewBox="0 0 16 16" fill="currentColor"> + <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/> + </svg> <%= link_to "@#{@owner.username}", user_profile_path(@owner.username), class: "text-brand-500 hover:underline font-medium" %> <span class="text-gray-500">/</span> <%= link_to @repository.name, repository_path(@owner.username, @repository.name), class: "text-brand-500 hover:underline font-semibold" %> + <% if @repository.is_private %> + <span class="badge-gray ml-1">Private</span> + <% end %> </div> + + <% if @repository.description.present? %> + <p class="text-sm text-gray-400 mb-4"><%= @repository.description %></p> + <% end %> + <div class="flex items-center gap-0 -mb-px"> - <%= link_to repository_path(@owner.username, @repository.name), class: "tab-item flex items-center gap-1.5" do %>Code<% end %> + <%= link_to repository_path(@owner.username, @repository.name), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/> + </svg> + Code + <% end %> <div class="tab-item active flex items-center gap-1.5"> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/> + </svg> Commits - <span class="badge-gray"><%= number_with_delimiter(@total) %></span> + <span class="badge-gray text-xs"><%= number_with_delimiter(@total) %></span> </div> + <%= link_to repository_cicd_path(@owner.username, @repository.name), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/> + </svg> + CI/CD + <% if @commit_count&.> 0 %> + <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> + <% end %> + <% end %> </div> </div> </div>
app/views/repositories/cicd.html.erb
+185
new file mode 100644 index 0000000..24fde7c --- /dev/null +++ b/app/views/repositories/cicd.html.erb @@ -0,0 +1,185 @@ +<% content_for :title, "CI/CD · #{@repository.full_name}" %> + +<div class="border-b border-surface-600 bg-surface-800"> + <div class="max-w-6xl mx-auto px-4 sm:px-6 pt-6 pb-0"> + <div class="flex items-center gap-2 text-sm mb-4"> + <svg class="w-4 h-4 text-gray-500" viewBox="0 0 16 16" fill="currentColor"> + <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/> + </svg> + <%= link_to "@#{@owner.username}", user_profile_path(@owner.username), + class: "text-brand-500 hover:underline font-medium" %> + <span class="text-gray-500">/</span> + <%= link_to @repository.name, repository_path(@owner.username, @repository.name), + class: "text-brand-500 hover:underline font-semibold" %> + <% if @repository.is_private %> + <span class="badge-gray ml-1">Private</span> + <% end %> + </div> + + <% if @repository.description.present? %> + <p class="text-sm text-gray-400 mb-4"><%= @repository.description %></p> + <% end %> + + <div class="flex items-center gap-0 -mb-px"> + <%= link_to repository_path(@owner.username, @repository.name), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/> + </svg> + Code + <% end %> + <% if @repository.initialized? %> + <%= link_to repository_commits_path(@owner.username, @repository.name, @repository.default_branch), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/> + </svg> + Commits + <% if @commit_count&.> 0 %> + <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> + <% end %> + <% end %> + <% end %> + <div class="tab-item active flex items-center gap-1.5"> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/> + </svg> + CI/CD + <% if @commit_count&.> 0 %> + <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> + <% end %> + </div> + </div> + </div> +</div> + +<div class="max-w-6xl mx-auto px-4 sm:px-6 py-6"> + <div class="grid gap-6 lg:grid-cols-[1.35fr_0.95fr]"> + <div class="space-y-6"> + <div class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4"> + <div class="card p-5"> + <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Success Rate</p> + <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:success_rate] %></p> + <p class="mt-1 text-xs text-emerald-400">+1.2% in the last 7 days</p> + </div> + <div class="card p-5"> + <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Avg Duration</p> + <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:avg_duration] %></p> + <p class="mt-1 text-xs text-gray-400">From build to deploy</p> + </div> + <div class="card p-5"> + <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Runs This Week</p> + <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:weekly_runs] %></p> + <p class="mt-1 text-xs text-gray-400">Across all branches</p> + </div> + <div class="card p-5"> + <p class="text-xs uppercase tracking-[0.18em] text-gray-500">Last Deploy</p> + <p class="mt-3 text-2xl font-semibold text-gray-100"><%= @pipeline_summary[:last_deploy] %></p> + <p class="mt-1 text-xs text-brand-400">Production is live</p> + </div> + </div> + + <div class="card overflow-hidden"> + <div class="flex items-center justify-between gap-4 border-b border-surface-600 px-5 py-4 bg-surface-600"> + <div> + <h2 class="text-sm font-semibold text-gray-100">Recent Pipeline Runs</h2> + <p class="mt-1 text-xs text-gray-400">Latest activity for <span class="text-gray-200"><%= @repository.full_name %></span></p> + </div> + <span class="badge-gray text-xs"><%= @branch %></span> + </div> + + <div> + <% @pipeline_runs.each do |run| %> + <% status_classes = case run[:status] + when "passed" then "bg-emerald-500/12 text-emerald-300 ring-1 ring-inset ring-emerald-500/20" + when "running" then "bg-sky-500/12 text-sky-300 ring-1 ring-inset ring-sky-500/20" + else "bg-rose-500/12 text-rose-300 ring-1 ring-inset ring-rose-500/20" + end %> + <div class="flex items-center justify-between gap-4 border-b border-surface-600/80 px-5 py-4 last:border-b-0"> + <div class="min-w-0"> + <div class="flex items-center gap-3"> + <p class="text-sm font-medium text-gray-100"><%= run[:name] %></p> + <span class="rounded-full px-2 py-0.5 text-[11px] font-medium <%= status_classes %>"><%= run[:status].capitalize %></span> + </div> + <p class="mt-1 text-xs text-gray-400"> + <span class="font-mono text-brand-400"><%= run[:sha] %></span> + on <span class="text-gray-200"><%= run[:ref] %></span> + by <span class="text-gray-200"><%= run[:actor] %></span> + </p> + </div> + <div class="shrink-0 text-right text-xs text-gray-400"> + <p><%= run[:duration] %></p> + <p class="mt-1 text-gray-500"><%= run[:started_at] %></p> + </div> + </div> + <% end %> + </div> + </div> + </div> + + <div class="space-y-6"> + <div class="card overflow-hidden"> + <div class="border-b border-surface-600 px-5 py-4 bg-surface-600"> + <h2 class="text-sm font-semibold text-gray-100">Environments</h2> + </div> + <div class="space-y-0"> + <% @environments.each do |environment| %> + <% env_classes = case environment[:status] + when "healthy" then "bg-emerald-400" + when "building" then "bg-sky-400" + else "bg-amber-400" + end %> + <div class="border-b border-surface-600/80 px-5 py-4 last:border-b-0"> + <div class="flex items-center justify-between gap-3"> + <div class="flex items-center gap-3"> + <span class="h-2.5 w-2.5 rounded-full <%= env_classes %>"></span> + <div> + <p class="text-sm font-medium text-gray-100"><%= environment[:name] %></p> + <p class="text-xs text-gray-400"><%= environment[:url] %></p> + </div> + </div> + <span class="badge-gray text-xs"><%= environment[:version] %></span> + </div> + <p class="mt-3 text-xs text-gray-500">Updated <%= environment[:updated_at] %></p> + </div> + <% end %> + </div> + </div> + + <div class="card overflow-hidden"> + <div class="border-b border-surface-600 px-5 py-4 bg-surface-600"> + <h2 class="text-sm font-semibold text-gray-100">Checks</h2> + </div> + <div class="space-y-0"> + <% @checks.each do |check| %> + <% icon = case check[:status] + when "passed" then "text-emerald-400" + when "running" then "text-sky-400" + else "text-rose-400" + end %> + <div class="flex items-start gap-3 border-b border-surface-600/80 px-5 py-4 last:border-b-0"> + <svg class="w-4 h-4 mt-0.5 shrink-0 <%= icon %>" viewBox="0 0 16 16" fill="currentColor"> + <path d="M8 1.5a6.5 6.5 0 1 0 6.5 6.5A6.507 6.507 0 0 0 8 1.5Zm3.03 5.28-3.5 3.75a.75.75 0 0 1-1.08.02L4.72 8.81a.75.75 0 0 1 1.06-1.06l1.18 1.18 2.95-3.17a.75.75 0 1 1 1.12 1Z"/> + </svg> + <div class="min-w-0"> + <div class="flex items-center gap-2"> + <p class="text-sm font-medium text-gray-100"><%= check[:name] %></p> + <span class="text-xs text-gray-500"><%= check[:status] %></span> + </div> + <p class="mt-1 text-xs text-gray-400"><%= check[:detail] %></p> + </div> + </div> + <% end %> + </div> + </div> + + <div class="card p-5"> + <h2 class="text-sm font-semibold text-gray-100">Deployment Policy</h2> + <p class="mt-2 text-sm text-gray-400"> + Pushes to <span class="font-mono text-gray-200">main</span> deploy automatically after all required checks pass. + Release branches require one approval before staging promotion. + </p> + </div> + </div> + </div> +</div>
app/views/repositories/show.html.erb
+10
index 18fd2b5..28e8340 100644 --- a/app/views/repositories/show.html.erb +++ b/app/views/repositories/show.html.erb @@ -42,6 +42,16 @@ <% end %> <% end %> <% end %> + <%= link_to repository_cicd_path(@owner.username, @repository.name), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/> + </svg> + CI/CD + <% if @commit_count&.> 0 %> + <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> + <% end %> + <% end %> </div> </div> </div>
app/views/repositories/tree.html.erb
+17
index b34aa63..5f81fd8 100644 --- a/app/views/repositories/tree.html.erb +++ b/app/views/repositories/tree.html.erb @@ -36,6 +36,23 @@ </svg> Code <% end %> + <%= link_to repository_commits_path(@owner.username, @repository.name, @branch), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/> + </svg> + Commits + <% end %> + <%= link_to repository_cicd_path(@owner.username, @repository.name), + class: "tab-item flex items-center gap-1.5" do %> + <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> + <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/> + </svg> + CI/CD + <% if @commit_count&.> 0 %> + <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> + <% end %> + <% end %> </div> </div> </div>
config/routes.rb
+1
index c700995..1eda314 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -33,6 +33,7 @@ Rails.application.routes.draw do # Repository routes (in order of specificity) get "/:username/:repository/commits/:branch", to: "commits#index", as: :repository_commits, constraints: { branch: /[^\/]+/, repository: /[^\/.][^\/]*/ } + get "/:username/:repository/ci-cd", to: "repositories#cicd", as: :repository_cicd get "/:username/:repository/commit/:sha", to: "commits#show", as: :repository_commit get "/:username/:repository/blob/:branch/*path", to: "blobs#show", as: :repository_blob, format: false get "/:username/:repository/raw/:branch/*path", to: "blobs#raw", as: :repository_blob_raw, format: false