fun_ci 2.1.1-aarch64-linux → 2.2.0-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +24 -1
- data/lib/fun_ci/agent/command_support.rb +7 -0
- data/lib/fun_ci/agent/commands.rb +2 -1
- data/lib/fun_ci/agent/due_in.rb +21 -0
- data/lib/fun_ci/agent/events_command.rb +14 -7
- data/lib/fun_ci/agent/job_events.rb +37 -0
- data/lib/fun_ci/agent/job_json.rb +16 -0
- data/lib/fun_ci/agent/job_report.rb +85 -0
- data/lib/fun_ci/agent/job_why.rb +59 -0
- data/lib/fun_ci/agent/job_why_json.rb +31 -0
- data/lib/fun_ci/agent/job_why_text.rb +51 -0
- data/lib/fun_ci/agent/jobs_command.rb +43 -0
- data/lib/fun_ci/agent/jobs_text.rb +50 -0
- data/lib/fun_ci/agent/live_pipeline.rb +7 -2
- data/lib/fun_ci/agent/options.rb +3 -3
- data/lib/fun_ci/agent/output.rb +14 -2
- data/lib/fun_ci/agent/snapshots.rb +16 -1
- data/lib/fun_ci/agent/span.rb +24 -0
- data/lib/fun_ci/agent/stage_summary.rb +10 -6
- data/lib/fun_ci/agent/status_command.rb +3 -2
- data/lib/fun_ci/agent/status_text.rb +19 -5
- data/lib/fun_ci/agent/why_command.rb +6 -2
- data/lib/fun_ci/cli.rb +1 -1
- data/lib/fun_ci/cli_help.rb +3 -1
- data/lib/fun_ci/console/board_data.rb +26 -13
- data/lib/fun_ci/console/console_state.rb +12 -6
- data/lib/fun_ci/console/job_message.rb +33 -0
- data/lib/fun_ci/console/job_order.rb +22 -0
- data/lib/fun_ci/console/job_rows.rb +21 -0
- data/lib/fun_ci/console/key_handler.rb +33 -14
- data/lib/fun_ci/console/paging.rb +26 -0
- data/lib/fun_ci/console/view.rb +18 -9
- data/lib/fun_ci/evidence/settings.rb +14 -7
- data/lib/fun_ci/evidence/settings_check.rb +14 -3
- data/lib/fun_ci/jobs/due.rb +33 -0
- data/lib/fun_ci/jobs/due_jobs.rb +26 -0
- data/lib/fun_ci/jobs/folders.rb +50 -0
- data/lib/fun_ci/jobs/job.rb +31 -0
- data/lib/fun_ci/jobs/job_fork.rb +45 -0
- data/lib/fun_ci/jobs/job_run.rb +85 -0
- data/lib/fun_ci/jobs/locks.rb +30 -0
- data/lib/fun_ci/jobs/site.rb +10 -0
- data/lib/fun_ci/jobs/standings.rb +46 -0
- data/lib/fun_ci/jobs/state.rb +26 -0
- data/lib/fun_ci/persistence/active_jobs.rb +54 -0
- data/lib/fun_ci/persistence/database.rb +14 -4
- data/lib/fun_ci/persistence/job_recorder.rb +47 -0
- data/lib/fun_ci/persistence/job_runs.rb +68 -0
- data/lib/fun_ci/persistence/raw_outputs.rb +3 -0
- data/lib/fun_ci/pipeline/pipeline_forker.rb +39 -10
- data/lib/fun_ci/pipeline/process_runner.rb +15 -5
- data/lib/fun_ci/pipeline/run_canceller.rb +24 -0
- data/lib/fun_ci/pipeline/slot.rb +1 -1
- data/lib/fun_ci/pipeline/stage_execution.rb +9 -4
- data/lib/fun_ci/pipeline/trigger_command.rb +7 -1
- data/lib/fun_ci/pipeline/worktree_prune.rb +8 -6
- data/lib/fun_ci/pipeline/worktrees.rb +8 -4
- data/lib/fun_ci/setup/agent_instructions.rb +3 -0
- data/lib/fun_ci/setup/project_config.rb +6 -0
- data/lib/fun_ci/setup/setup_checker.rb +7 -1
- data/lib/fun_ci/version.rb +1 -1
- data/libexec/fun-ci-renderer +0 -0
- metadata +28 -1
|
@@ -5,24 +5,41 @@ require_relative "../persistence/pipeline_recorder"
|
|
|
5
5
|
require_relative "trigger_params"
|
|
6
6
|
require_relative "../setup/project_config"
|
|
7
7
|
require_relative "../trunk/first_fetch"
|
|
8
|
+
require_relative "../jobs/due_jobs"
|
|
9
|
+
require_relative "../jobs/job_fork"
|
|
8
10
|
|
|
9
11
|
module FunCi
|
|
10
12
|
module Pipeline
|
|
11
13
|
class PipelineForker
|
|
12
|
-
# A run started,
|
|
13
|
-
|
|
14
|
+
# A run started, what to say before the project's first fetch of its
|
|
15
|
+
# trunk, if this is it, and why the daily and weekly jobs didn't start,
|
|
16
|
+
# if they didn't.
|
|
17
|
+
Forked = Data.define(:notice, :jobs)
|
|
18
|
+
|
|
19
|
+
class Forked
|
|
20
|
+
def initialize(notice:, jobs: nil) = super
|
|
21
|
+
end
|
|
14
22
|
|
|
15
23
|
# Answers a Forked, or false in a project not set up for fun-ci. What the
|
|
16
|
-
# run prints goes nowhere, so the notice is worked out here, before the
|
|
17
|
-
|
|
24
|
+
# run prints goes nowhere, so the notice is worked out here, before the
|
|
25
|
+
# fork. The project's due jobs start beside the run, each in a process
|
|
26
|
+
# of its own (design.md, Daily and weekly jobs), once the run has
|
|
27
|
+
# started, and trouble starting them never stops it. jobs: what starts
|
|
28
|
+
# them, given the commit and the database's path.
|
|
29
|
+
def self.fork_pipeline(commit_hash:, branch:, db_path:, jobs: method(:start_due_jobs))
|
|
18
30
|
return false unless Setup::ProjectConfig.new(Dir.pwd).validate.empty?
|
|
19
31
|
|
|
20
32
|
notice = first_fetch(db_path)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
Process.detach(fork { run_in_child(commit_hash: commit_hash, branch: branch, db_path: db_path) })
|
|
34
|
+
Forked.new(notice: notice, jobs: trouble { jobs.call(Commit.new(sha: commit_hash, branch: branch), db_path) })
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# What went wrong starting the jobs, or nil.
|
|
38
|
+
def self.trouble
|
|
39
|
+
yield
|
|
40
|
+
nil
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
"fun-ci: the daily and weekly jobs didn't start: #{e.message}"
|
|
26
43
|
end
|
|
27
44
|
|
|
28
45
|
# The connection closes before the fork, which must not inherit it.
|
|
@@ -33,6 +50,18 @@ module FunCi
|
|
|
33
50
|
db&.close
|
|
34
51
|
end
|
|
35
52
|
|
|
53
|
+
# Which jobs are due is read before any fork, which must not inherit the connection.
|
|
54
|
+
def self.start_due_jobs(commit, db_path)
|
|
55
|
+
due_jobs(db_path).each { |job| Jobs::JobFork.start(job, commit, project: Dir.pwd, db_path: db_path) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.due_jobs(db_path)
|
|
59
|
+
db = Persistence::Database.connection(db_path)
|
|
60
|
+
Jobs::DueJobs.new(Dir.pwd, db, now: Time.now).list
|
|
61
|
+
ensure
|
|
62
|
+
db&.close
|
|
63
|
+
end
|
|
64
|
+
|
|
36
65
|
# Trigger requires this file, through TriggerCommand, so it is loaded
|
|
37
66
|
# here, where it is used, rather than above.
|
|
38
67
|
def self.run_in_child(commit_hash:, branch:, db_path:)
|
|
@@ -49,7 +78,7 @@ module FunCi
|
|
|
49
78
|
Trigger.new(project: Dir.pwd, commit: Commit.new(sha: commit_hash, branch: branch),
|
|
50
79
|
io: Io.new(stdout: File.open(File::NULL, "w")), seams: Seams.new(recorder: recorder))
|
|
51
80
|
end
|
|
52
|
-
private_class_method :trigger, :first_fetch
|
|
81
|
+
private_class_method :trigger, :first_fetch, :start_due_jobs, :due_jobs, :trouble
|
|
53
82
|
end
|
|
54
83
|
end
|
|
55
84
|
end
|
|
@@ -23,16 +23,24 @@ module FunCi
|
|
|
23
23
|
DRAIN_SECONDS = 1
|
|
24
24
|
|
|
25
25
|
# Where the command runs, what it finds in its environment besides
|
|
26
|
-
# fun-ci's own, the window what it prints is written to,
|
|
27
|
-
# with its pid when it runs over budget, before it is killed
|
|
28
|
-
|
|
26
|
+
# fun-ci's own, the window what it prints is written to, what to do
|
|
27
|
+
# with its pid when it runs over budget, before it is killed, and the
|
|
28
|
+
# open files it holds as long as it runs, such as a lock.
|
|
29
|
+
Launch = Data.define(:chdir, :env, :output, :before_kill, :held)
|
|
29
30
|
|
|
30
31
|
class Launch
|
|
31
32
|
def initialize(**given)
|
|
32
|
-
super(chdir: Dir.pwd, env: {}, output: OutputWindow.in_memory, before_kill: nil, **given)
|
|
33
|
+
super(chdir: Dir.pwd, env: {}, output: OutputWindow.in_memory, before_kill: nil, held: [], **given)
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
37
|
+
# Where the first file a command holds is open in it: past the gate's 9.
|
|
38
|
+
FIRST_HELD = 10
|
|
39
|
+
|
|
40
|
+
# { descriptor in the command => file } for the files it holds. Not their
|
|
41
|
+
# own descriptors, which in a process with few files open may be the gate's.
|
|
42
|
+
def self.held_descriptors(files) = files.each_with_index.to_h { |file, index| [FIRST_HELD + index, file] }
|
|
43
|
+
|
|
36
44
|
# A command started and let go, and the pipe that carries what it prints.
|
|
37
45
|
Started = Data.define(:pid, :reader)
|
|
38
46
|
|
|
@@ -70,9 +78,11 @@ module FunCi
|
|
|
70
78
|
|
|
71
79
|
def spawn_gated(cmd, writer, gate, launch)
|
|
72
80
|
Process.spawn(GitEnvironment::CLEAN.merge(launch.env), format(GATED, cmd),
|
|
73
|
-
out: writer, err: writer, 9 => gate.child_end, pgroup: true, chdir: launch.chdir)
|
|
81
|
+
out: writer, err: writer, 9 => gate.child_end, pgroup: true, chdir: launch.chdir, **held(launch))
|
|
74
82
|
end
|
|
75
83
|
|
|
84
|
+
def held(launch) = ProcessRunner.held_descriptors(launch.held)
|
|
85
|
+
|
|
76
86
|
# The reader may be closed while this thread still reads, once a killed
|
|
77
87
|
# command's output has drained or stopped coming.
|
|
78
88
|
def read_until_closed(reader, printed)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../persistence/active_runs"
|
|
4
|
+
require_relative "../persistence/active_jobs"
|
|
4
5
|
require_relative "../persistence/run_status"
|
|
5
6
|
require_relative "../persistence/write_trouble"
|
|
6
7
|
require_relative "slot_lock"
|
|
@@ -36,6 +37,26 @@ module FunCi
|
|
|
36
37
|
# The next poll looks again.
|
|
37
38
|
end
|
|
38
39
|
|
|
40
|
+
# Stops a daily or weekly job's processes and records it cancelled,
|
|
41
|
+
# unless it has finished meanwhile; a group its runner recorded while
|
|
42
|
+
# this looked is stopped once the runner is dead, as a run's late stages are.
|
|
43
|
+
def cancel_job(db, id)
|
|
44
|
+
Persistence::ActiveJobs.with_id(db, id).each do |job|
|
|
45
|
+
stop(job)
|
|
46
|
+
Persistence::ActiveJobs.with_id(db, id).each { |now| kill_late(job, now) }
|
|
47
|
+
Persistence::ActiveJobs.cancelled(db, id)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Records failed each daily or weekly job still running whose lock
|
|
52
|
+
# nobody holds: its process is gone (acceptance-tests.md, AT-13.6).
|
|
53
|
+
def record_dead_jobs(db)
|
|
54
|
+
Persistence::ActiveJobs.running(db).filter_map { |id, lock| id unless @slot_held.call(lock) }
|
|
55
|
+
.each { |id| Persistence::ActiveJobs.died(db, id) }
|
|
56
|
+
rescue SQLite3::BusyException, *Persistence::WriteTrouble::UNWRITABLE
|
|
57
|
+
# The next poll looks again.
|
|
58
|
+
end
|
|
59
|
+
|
|
39
60
|
def stop(run)
|
|
40
61
|
return unless alive?(run)
|
|
41
62
|
|
|
@@ -53,6 +74,9 @@ module FunCi
|
|
|
53
74
|
end
|
|
54
75
|
end
|
|
55
76
|
|
|
77
|
+
# The groups recorded since `before` was read.
|
|
78
|
+
def kill_late(before, now) = (now.stage_groups - before.stage_groups).each { |group| kill(-group) }
|
|
79
|
+
|
|
56
80
|
def alive?(run) = run.slot_lock.nil? || @slot_held.call(run.slot_lock)
|
|
57
81
|
|
|
58
82
|
# Whether a process with this pid exists; one this user may not signal does.
|
data/lib/fun_ci/pipeline/slot.rb
CHANGED
|
@@ -6,7 +6,7 @@ module FunCi
|
|
|
6
6
|
# file. The fast suite and the slow suite each hold it; it frees when the
|
|
7
7
|
# last of them lets go. A process that dies lets go with it.
|
|
8
8
|
class Slot
|
|
9
|
-
attr_reader :path, :lock_file
|
|
9
|
+
attr_reader :path, :lock_file, :lock
|
|
10
10
|
|
|
11
11
|
# +lock_file+ names the lock on disk; nil for a slot with nothing to lock.
|
|
12
12
|
def initialize(path, lock, lock_file = nil)
|
|
@@ -7,12 +7,18 @@ module FunCi
|
|
|
7
7
|
module Pipeline
|
|
8
8
|
# Runs a stage that has been started, in `dir`, with a stage directory of
|
|
9
9
|
# its own, and records how it ended while it still holds both. The same
|
|
10
|
-
# for every stage, the slow suite in its forked child included
|
|
10
|
+
# for every stage, the slow suite in its forked child included, and for
|
|
11
|
+
# a daily or weekly job.
|
|
11
12
|
class StageExecution
|
|
12
|
-
|
|
13
|
+
# launching: what the script is launched with besides its output window
|
|
14
|
+
# (ProcessRunner::Launch): what it is told about itself, by default its
|
|
15
|
+
# stage's name in FUN_CI_STAGE (acceptance-tests.md, AT-10.7), and the
|
|
16
|
+
# files it holds open.
|
|
17
|
+
def initialize(seams:, dir:, commit:, launching: {})
|
|
13
18
|
@seams = seams
|
|
14
19
|
@dir = dir
|
|
15
20
|
@commit = commit
|
|
21
|
+
@launching = launching
|
|
16
22
|
end
|
|
17
23
|
|
|
18
24
|
# Answers [the outcome recorded, what the stage printed].
|
|
@@ -36,10 +42,9 @@ module FunCi
|
|
|
36
42
|
StageEnd::Finished.new(output: output, status: status, timed_out: timed_out, overrun: overrun)
|
|
37
43
|
end
|
|
38
44
|
|
|
39
|
-
# The stage learns its name from FUN_CI_STAGE (acceptance-tests.md, AT-10.7).
|
|
40
45
|
def execute(stage, command, stage_dir, before_kill, &)
|
|
41
46
|
window = stage_dir.window
|
|
42
|
-
launch = ProcessRunner::Launch.new(env: { "FUN_CI_STAGE" => stage }, output: window,
|
|
47
|
+
launch = ProcessRunner::Launch.new(env: { "FUN_CI_STAGE" => stage }, **@launching, output: window,
|
|
43
48
|
before_kill: before_kill)
|
|
44
49
|
@seams.executor(@dir).call(command, @seams.budgets[stage], launch, &)
|
|
45
50
|
ensure
|
|
@@ -56,10 +56,16 @@ module FunCi
|
|
|
56
56
|
return 0 unless forked
|
|
57
57
|
|
|
58
58
|
say_how_to_wait(commit.sha[0, 7])
|
|
59
|
-
|
|
59
|
+
say(forked)
|
|
60
60
|
0
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
# The first fetch's notice, and on stderr, why the jobs didn't start.
|
|
64
|
+
def say(forked)
|
|
65
|
+
@io.stdout.puts(forked.notice) if forked.notice
|
|
66
|
+
@io.stderr.puts(forked.jobs) if forked.jobs
|
|
67
|
+
end
|
|
68
|
+
|
|
63
69
|
def say_how_to_wait(sha) = @io.stdout.puts("fun-ci: testing #{sha}. Verdict: fun-ci wait #{sha} --need all")
|
|
64
70
|
end
|
|
65
71
|
end
|
|
@@ -5,8 +5,9 @@ require_relative "worktrees"
|
|
|
5
5
|
|
|
6
6
|
module FunCi
|
|
7
7
|
module Pipeline
|
|
8
|
-
# Removes every slot of a project's worktree pool
|
|
9
|
-
#
|
|
8
|
+
# Removes every slot of a project's worktree pool and every daily or
|
|
9
|
+
# weekly job's worktree, and git's entries for them, when no run or job
|
|
10
|
+
# holds one. It takes each slot's lock first, so a run
|
|
10
11
|
# starting meanwhile waits until the slot is gone and then checks it out
|
|
11
12
|
# afresh.
|
|
12
13
|
class WorktreePrune
|
|
@@ -16,8 +17,8 @@ module FunCi
|
|
|
16
17
|
@worktrees = worktrees
|
|
17
18
|
end
|
|
18
19
|
|
|
19
|
-
# How many
|
|
20
|
-
#
|
|
20
|
+
# How many worktrees it removed. Raises Busy, removing nothing, while a
|
|
21
|
+
# run or a job holds one.
|
|
21
22
|
def run
|
|
22
23
|
locks = take_locks
|
|
23
24
|
locks.each { |lock| FileUtils.rm_rf(lock.path.delete_suffix(".lock")) }
|
|
@@ -37,12 +38,13 @@ module FunCi
|
|
|
37
38
|
next if locks.last.flock(File::LOCK_EX | File::LOCK_NB)
|
|
38
39
|
|
|
39
40
|
locks.each(&:close)
|
|
40
|
-
raise Busy, "
|
|
41
|
+
raise Busy, "fun-ci is running something in #{path}"
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
def slot_paths
|
|
45
|
-
Dir.glob(File.join(@worktrees.root, "slot-*"))
|
|
46
|
+
(Dir.glob(File.join(@worktrees.root, "slot-*")) + Dir.glob(File.join(@worktrees.jobs_root, "*")))
|
|
47
|
+
.map { |path| path.delete_suffix(".lock") }.uniq
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
end
|
|
@@ -13,10 +13,10 @@ module FunCi
|
|
|
13
13
|
@project_root = project_root
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def root
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
def root = File.join(fun_ci_dir, "worktrees")
|
|
17
|
+
|
|
18
|
+
# Where each daily and weekly job has a worktree of its own (Jobs::Locks).
|
|
19
|
+
def jobs_root = File.join(fun_ci_dir, "jobs")
|
|
20
20
|
|
|
21
21
|
# Leaves +path+ as a clean detached checkout of +sha+. Ignored files stay,
|
|
22
22
|
# so caches such as vendor/bundle survive between runs in the same slot.
|
|
@@ -32,6 +32,10 @@ module FunCi
|
|
|
32
32
|
|
|
33
33
|
private
|
|
34
34
|
|
|
35
|
+
def fun_ci_dir
|
|
36
|
+
File.join(File.expand_path(git(@project_root, "rev-parse", "--git-common-dir").strip, @project_root), "fun-ci")
|
|
37
|
+
end
|
|
38
|
+
|
|
35
39
|
def add(path, sha) = git(@project_root, "worktree", "add", "--detach", "--force", path, sha)
|
|
36
40
|
|
|
37
41
|
def git(dir, *args)
|
|
@@ -19,6 +19,9 @@ module FunCi
|
|
|
19
19
|
the commit conflicts with the trunk, which has to be integrated first,
|
|
20
20
|
as it prints.
|
|
21
21
|
`fun-ci runs` lists recent runs, and `fun-ci status` says where one stands.
|
|
22
|
+
`fun-ci jobs` lists the daily and weekly jobs, which run beside the
|
|
23
|
+
pipeline and never hold up a verdict, and `fun-ci why --job NAME` says
|
|
24
|
+
why one failed.
|
|
22
25
|
MD
|
|
23
26
|
|
|
24
27
|
def self.file_for(names) = names.include?("CLAUDE.md") && !names.include?("AGENTS.md") ? "CLAUDE.md" : "AGENTS.md"
|
|
@@ -4,6 +4,7 @@ require "shellwords"
|
|
|
4
4
|
require_relative "settings"
|
|
5
5
|
require_relative "../evidence/settings"
|
|
6
6
|
require_relative "../evidence/start"
|
|
7
|
+
require_relative "../jobs/folders"
|
|
7
8
|
|
|
8
9
|
module FunCi
|
|
9
10
|
module Setup
|
|
@@ -37,6 +38,11 @@ module FunCi
|
|
|
37
38
|
# may hold, such as JSON logs.
|
|
38
39
|
def any_project_presets = preset_candidates.reject(&:because).map { |found| found.preset.name }
|
|
39
40
|
|
|
41
|
+
# The daily and weekly jobs that can run, and why any other can't
|
|
42
|
+
# (design.md, Daily and weekly jobs); neither stops a pipeline.
|
|
43
|
+
def jobs = Jobs::Folders.new(@project_root).jobs
|
|
44
|
+
def job_errors = Jobs::Folders.new(@project_root).errors
|
|
45
|
+
|
|
40
46
|
def worktree_slots = settings.worktree_slots
|
|
41
47
|
def trunk = settings.trunk
|
|
42
48
|
def trunk_fetch = settings.trunk_fetch
|
|
@@ -22,10 +22,11 @@ module FunCi
|
|
|
22
22
|
|
|
23
23
|
# Warnings are printed but don't fail the check.
|
|
24
24
|
def run
|
|
25
|
-
errors = @config.validate + @config.evidence_errors
|
|
25
|
+
errors = @config.validate + @config.evidence_errors + @config.job_errors
|
|
26
26
|
@stdout.puts(errors.empty? ? "All OK. The project is configured." : errors)
|
|
27
27
|
@stdout.puts(@trunk.lines)
|
|
28
28
|
list_presets
|
|
29
|
+
list_jobs
|
|
29
30
|
@hooks.warnings.each { |warning| @stdout.puts "Warning: #{warning}" }
|
|
30
31
|
errors.empty? ? 0 : 1
|
|
31
32
|
end
|
|
@@ -36,6 +37,11 @@ module FunCi
|
|
|
36
37
|
lists = { "this project" => @config.presets, "any project's output" => @config.any_project_presets }
|
|
37
38
|
lists.each { |what, names| @stdout.puts "Evidence presets for #{what}: #{names.join(", ")}" if names.any? }
|
|
38
39
|
end
|
|
40
|
+
|
|
41
|
+
def list_jobs
|
|
42
|
+
jobs = @config.jobs
|
|
43
|
+
@stdout.puts "Jobs: #{jobs.map { |job| "#{job.name} (#{job.cadence})" }.join(", ")}" if jobs.any?
|
|
44
|
+
end
|
|
39
45
|
end
|
|
40
46
|
end
|
|
41
47
|
end
|
data/lib/fun_ci/version.rb
CHANGED
data/libexec/fun-ci-renderer
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fun_ci
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Erik Thyge Madsen
|
|
@@ -67,11 +67,20 @@ files:
|
|
|
67
67
|
- lib/fun_ci/agent/commands.rb
|
|
68
68
|
- lib/fun_ci/agent/context.rb
|
|
69
69
|
- lib/fun_ci/agent/digest.rb
|
|
70
|
+
- lib/fun_ci/agent/due_in.rb
|
|
70
71
|
- lib/fun_ci/agent/events.rb
|
|
71
72
|
- lib/fun_ci/agent/events_command.rb
|
|
72
73
|
- lib/fun_ci/agent/evidence_text.rb
|
|
73
74
|
- lib/fun_ci/agent/exit_code.rb
|
|
74
75
|
- lib/fun_ci/agent/git.rb
|
|
76
|
+
- lib/fun_ci/agent/job_events.rb
|
|
77
|
+
- lib/fun_ci/agent/job_json.rb
|
|
78
|
+
- lib/fun_ci/agent/job_report.rb
|
|
79
|
+
- lib/fun_ci/agent/job_why.rb
|
|
80
|
+
- lib/fun_ci/agent/job_why_json.rb
|
|
81
|
+
- lib/fun_ci/agent/job_why_text.rb
|
|
82
|
+
- lib/fun_ci/agent/jobs_command.rb
|
|
83
|
+
- lib/fun_ci/agent/jobs_text.rb
|
|
75
84
|
- lib/fun_ci/agent/live_pipeline.rb
|
|
76
85
|
- lib/fun_ci/agent/next_step.rb
|
|
77
86
|
- lib/fun_ci/agent/options.rb
|
|
@@ -83,6 +92,7 @@ files:
|
|
|
83
92
|
- lib/fun_ci/agent/runs_command.rb
|
|
84
93
|
- lib/fun_ci/agent/runs_text.rb
|
|
85
94
|
- lib/fun_ci/agent/snapshots.rb
|
|
95
|
+
- lib/fun_ci/agent/span.rb
|
|
86
96
|
- lib/fun_ci/agent/stage_summary.rb
|
|
87
97
|
- lib/fun_ci/agent/status_command.rb
|
|
88
98
|
- lib/fun_ci/agent/status_json.rb
|
|
@@ -110,10 +120,14 @@ files:
|
|
|
110
120
|
- lib/fun_ci/console/console_loop.rb
|
|
111
121
|
- lib/fun_ci/console/console_session.rb
|
|
112
122
|
- lib/fun_ci/console/console_state.rb
|
|
123
|
+
- lib/fun_ci/console/job_message.rb
|
|
124
|
+
- lib/fun_ci/console/job_order.rb
|
|
125
|
+
- lib/fun_ci/console/job_rows.rb
|
|
113
126
|
- lib/fun_ci/console/key_handler.rb
|
|
114
127
|
- lib/fun_ci/console/launcher.rb
|
|
115
128
|
- lib/fun_ci/console/milestone_events.rb
|
|
116
129
|
- lib/fun_ci/console/milestones.rb
|
|
130
|
+
- lib/fun_ci/console/paging.rb
|
|
117
131
|
- lib/fun_ci/console/renderer_lookup.rb
|
|
118
132
|
- lib/fun_ci/console/renderer_process.rb
|
|
119
133
|
- lib/fun_ci/console/row_order.rb
|
|
@@ -205,8 +219,21 @@ files:
|
|
|
205
219
|
- lib/fun_ci/evidence/stamp.rb
|
|
206
220
|
- lib/fun_ci/evidence/start.rb
|
|
207
221
|
- lib/fun_ci/evidence/worktree.rb
|
|
222
|
+
- lib/fun_ci/jobs/due.rb
|
|
223
|
+
- lib/fun_ci/jobs/due_jobs.rb
|
|
224
|
+
- lib/fun_ci/jobs/folders.rb
|
|
225
|
+
- lib/fun_ci/jobs/job.rb
|
|
226
|
+
- lib/fun_ci/jobs/job_fork.rb
|
|
227
|
+
- lib/fun_ci/jobs/job_run.rb
|
|
228
|
+
- lib/fun_ci/jobs/locks.rb
|
|
229
|
+
- lib/fun_ci/jobs/site.rb
|
|
230
|
+
- lib/fun_ci/jobs/standings.rb
|
|
231
|
+
- lib/fun_ci/jobs/state.rb
|
|
232
|
+
- lib/fun_ci/persistence/active_jobs.rb
|
|
208
233
|
- lib/fun_ci/persistence/active_runs.rb
|
|
209
234
|
- lib/fun_ci/persistence/database.rb
|
|
235
|
+
- lib/fun_ci/persistence/job_recorder.rb
|
|
236
|
+
- lib/fun_ci/persistence/job_runs.rb
|
|
210
237
|
- lib/fun_ci/persistence/null_recorder.rb
|
|
211
238
|
- lib/fun_ci/persistence/output_tail.rb
|
|
212
239
|
- lib/fun_ci/persistence/pipeline_recorder.rb
|