fun_ci 2.0.0 → 2.0.2
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 +50 -0
- data/README.md +4 -0
- data/lib/fun_ci/agent/git.rb +3 -2
- data/lib/fun_ci/agent/report_stage.rb +2 -4
- data/lib/fun_ci/persistence/active_runs.rb +2 -2
- data/lib/fun_ci/persistence/database.rb +4 -0
- data/lib/fun_ci/persistence/stage_job.rb +3 -1
- data/lib/fun_ci/pipeline/trigger_params.rb +8 -0
- data/lib/fun_ci/setup/gradle_linter_detector.rb +23 -0
- data/lib/fun_ci/setup/installer.rb +10 -10
- data/lib/fun_ci/setup/lint_detection.rb +32 -0
- data/lib/fun_ci/setup/maven_linter_detector.rb +4 -2
- data/lib/fun_ci/setup/stage_templates/managed.rb +12 -7
- data/lib/fun_ci/setup/stage_templates/native.rb +1 -1
- data/lib/fun_ci/setup/stage_templates/shell.rb +12 -3
- data/lib/fun_ci/setup/stage_templates.rb +1 -1
- data/lib/fun_ci/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ec70009244a286fd23264c7cd99becf5a5a437ee8fb2a636652d1050f2b4d78
|
|
4
|
+
data.tar.gz: c354caa2011c5d7d8d39d2637f9c3423cae3c7e8a8c6fcce83232aa83d169cd5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aa78fbd513340af9d0cb8cd1c0d071a6eb2c487f4fb2216a7108acdc3b71f1ba19682cb7746f5fdb024a1a0a7ea8f32d15c76f41f64a900f16ab6fc8594beaec
|
|
7
|
+
data.tar.gz: efb2b61788bd0e2ba361646a2391976c4fd29de3b91f1256d9425a5efc0687b6b731ccc6bbeeca22f52e12a091d705f10035298e2a622be63ef714a8f55f59d9
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.0.2] - 2026-09-29
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- In a Gradle project set up by `fun-ci init`, the fast suite could fail
|
|
14
|
+
before running a test, with Gradle unable to hash a file in its own build
|
|
15
|
+
directory (`build/kotlin/compileTestKotlin/...`). The fast and slow suites
|
|
16
|
+
run side by side in one worktree, and both compiled the test code into the
|
|
17
|
+
same place, each deleting what the other was reading. The build script now
|
|
18
|
+
compiles the test code (`./gradlew assemble testClasses`), so neither suite
|
|
19
|
+
has to. Maven, .NET, Elixir, Dart and Swift projects could clash the same
|
|
20
|
+
way, and their scripts change too: Maven builds with `mvn test-compile` and
|
|
21
|
+
runs `mvn surefire:test` and `mvn failsafe:integration-test
|
|
22
|
+
failsafe:verify`, so its slow suite now runs only the integration tests
|
|
23
|
+
failsafe finds (the classes named `*IT`) rather than every test again;
|
|
24
|
+
Elixir compiles its test environment in the build; Dart precompiles its test
|
|
25
|
+
runner and runs the slow suite from source; the .NET and Swift suites run
|
|
26
|
+
with `--no-build` and `--skip-build`.
|
|
27
|
+
- Lint runs side by side with the build, and the lint `fun-ci init` wrote for
|
|
28
|
+
Maven (`mvn verify -DskipTests`) and .NET (`dotnet format`) compiled into
|
|
29
|
+
the same directories as the build. Lint now works on the source code alone.
|
|
30
|
+
Maven's runs the linter the POM configures (detekt, ktlint, checkstyle or
|
|
31
|
+
PMD) or else `mvn validate`, and no longer picks spotbugs, which reads
|
|
32
|
+
compiled classes. .NET's checks whitespace with `dotnet format whitespace
|
|
33
|
+
--folder`. Gradle's runs ktlint, spotless or detekt when the build applies
|
|
34
|
+
one, and otherwise says there is none, where it ran `check`, which compiles.
|
|
35
|
+
A linter that needs compiled code goes in `build.sh` or `fast.sh`.
|
|
36
|
+
- Which stages run side by side, and so what each may read and write, is now
|
|
37
|
+
spelled out: in a new section of `docs/design.md`, in the README, in what
|
|
38
|
+
`fun-ci init` prints, and in a comment at the top of each script it writes.
|
|
39
|
+
Scripts already in `.fun-ci/` are left as they are, so an existing project
|
|
40
|
+
picks up these fixes by editing them to match `docs/stacks.md`.
|
|
41
|
+
|
|
42
|
+
## [2.0.1] - 2026-09-29
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- `fun-ci console` could show a blank screen and stay that way. When a new
|
|
46
|
+
commit cancelled a run in the same second one of its stages started, the
|
|
47
|
+
stage was recorded as ending before it began. The renderer rejected the
|
|
48
|
+
negative duration and, with it, every board Ruby sent, so nothing was drawn
|
|
49
|
+
while that run was listed; the only sign was a line per second in
|
|
50
|
+
`.fun-ci/console.log`. Ends are now recorded to the millisecond, and a stage
|
|
51
|
+
already recorded that way reads as taking no time, so an existing database
|
|
52
|
+
needs no repair. `fun-ci status`, `why` and `events` no longer report a
|
|
53
|
+
negative time for such a stage either.
|
|
54
|
+
- A commit made on a detached HEAD, as every commit a rebase replays is, was
|
|
55
|
+
recorded with no branch name, so `fun-ci status` ended in "on" and the
|
|
56
|
+
console showed a gap where the branch goes. Such runs are now on the branch
|
|
57
|
+
`detached`, whether a hook or `fun-ci wait` started them, and runs already
|
|
58
|
+
recorded without a name are renamed when fun-ci next opens its database.
|
|
59
|
+
|
|
10
60
|
## [2.0.0] - 2026-09-29
|
|
11
61
|
|
|
12
62
|
fun-ci 2.0 has two ways in. People watch a new console, drawn by a Rust
|
data/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
[](https://badge.fury.io/rb/fun_ci)
|
|
2
|
+
|
|
1
3
|
# Fun-CI
|
|
2
4
|
|
|
3
5
|
Opinionated local CI that checks your code before it leaves your machine. Every commit runs lint, build, a fast suite and a slow suite on your own computer, each held to a strict time budget, so the feedback stays fast.
|
|
@@ -41,6 +43,8 @@ Upgrading from 1.x? Read [Upgrading to 2.0](#upgrading-to-20) first.
|
|
|
41
43
|
| Fast | 10 s | after lint and build pass | the push |
|
|
42
44
|
| Slow | 5 min | in the background, beside the fast suite | nothing |
|
|
43
45
|
|
|
46
|
+
Lint and build run side by side on the commit's checkout, and then the fast and slow suites run side by side on what the build left, all in one worktree. Two stages running at once must not write the same files, so `lint.sh` works on the source code only and `build.sh` compiles everything the suites need, test code included. A linter that needs compiled code belongs in `build.sh` or `fast.sh`. The scripts `fun-ci init` writes keep to this; [Stages side by side](docs/design.md#stages-side-by-side) has the details.
|
|
47
|
+
|
|
44
48
|
A stage that overruns its budget is killed and reported as over budget, in yellow rather than red: a fast suite that takes 12 seconds has grown too heavy, which is a different problem from a failing test.
|
|
45
49
|
|
|
46
50
|
After each commit, the `post-commit` hook starts the pipeline in the background and returns at once, so a commit is never held up. The `pre-push` hook waits for the verdict of each commit you push and stops the push if lint, build or the fast suite failed. A commit whose run has already finished goes straight through. If fun-ci isn't installed, both hooks say so and let git carry on.
|
data/lib/fun_ci/agent/git.rb
CHANGED
|
@@ -16,8 +16,9 @@ module FunCi
|
|
|
16
16
|
def subject(sha) = git("log", "-1", "--format=%s", sha).to_s
|
|
17
17
|
def toplevel = File.realpath(git("rev-parse", "--show-toplevel"))
|
|
18
18
|
|
|
19
|
-
# The branch checked out, as the git hooks name it
|
|
20
|
-
|
|
19
|
+
# The branch checked out, as the git hooks name it: "" when HEAD is
|
|
20
|
+
# detached, which trigger names (Pipeline::Commit).
|
|
21
|
+
def branch = git("branch", "--show-current").to_s
|
|
21
22
|
|
|
22
23
|
private
|
|
23
24
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
-
require "time"
|
|
5
4
|
require_relative "../evidence/document"
|
|
5
|
+
require_relative "../persistence/stage_job"
|
|
6
6
|
|
|
7
7
|
module FunCi
|
|
8
8
|
module Agent
|
|
@@ -62,9 +62,7 @@ module FunCi
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def self.seconds(job)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
(Time.parse(job[:completed_at]) - Time.parse(job[:started_at])).round(1)
|
|
65
|
+
Persistence::StageJob.elapsed_duration(job)&.round(1)
|
|
68
66
|
end
|
|
69
67
|
private_class_method :kept, :seconds
|
|
70
68
|
end
|
|
@@ -42,12 +42,12 @@ module FunCi
|
|
|
42
42
|
# Records the slow stage failed, unless its result was recorded meanwhile.
|
|
43
43
|
def self.slow_suite_died(db, job_id)
|
|
44
44
|
db.execute("UPDATE stage_jobs SET status = 'failed', completed_at = ? WHERE id = ? AND status = 'running'",
|
|
45
|
-
[Time.now.utc.iso8601, job_id])
|
|
45
|
+
[Time.now.utc.iso8601(3), job_id])
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def self.cancelled(db, run)
|
|
49
49
|
db.execute("UPDATE stage_jobs SET status = 'cancelled', completed_at = ? " \
|
|
50
|
-
"WHERE pipeline_run_id = ? AND #{ACTIVE}", [Time.now.utc.iso8601, run.id])
|
|
50
|
+
"WHERE pipeline_run_id = ? AND #{ACTIVE}", [Time.now.utc.iso8601(3), run.id])
|
|
51
51
|
PipelineRun.update_status(db, run.id, "cancelled")
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -50,9 +50,13 @@ module FunCi
|
|
|
50
50
|
with_setup_lock(db.filename("main")) do
|
|
51
51
|
[PIPELINE_RUNS_TABLE, STAGE_JOBS_TABLE].each { |table| db.execute(table) }
|
|
52
52
|
ADDED_COLUMNS.each { |table, column, type| add_column_if_missing(db, table, column, type) }
|
|
53
|
+
db.execute(NAME_DETACHED)
|
|
53
54
|
end
|
|
54
55
|
end
|
|
55
56
|
|
|
57
|
+
# Runs started on a detached HEAD before 2.0.1 were kept with no branch name.
|
|
58
|
+
NAME_DETACHED = "UPDATE pipeline_runs SET branch = 'detached' WHERE branch = ''"
|
|
59
|
+
|
|
56
60
|
def self.with_setup_lock(db_path)
|
|
57
61
|
File.open("#{db_path}.setup-lock", File::RDWR | File::CREAT, 0o644) do |lock|
|
|
58
62
|
lock.flock(File::LOCK_EX)
|
|
@@ -76,10 +76,12 @@ module FunCi
|
|
|
76
76
|
[new_status, Time.now.utc.iso8601(3), id])
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
+
# Never less than nothing: rows kept before ends were recorded to the
|
|
80
|
+
# millisecond can end in the second they started, before their start.
|
|
79
81
|
def self.elapsed_duration(job)
|
|
80
82
|
return nil unless job[:started_at] && job[:completed_at]
|
|
81
83
|
|
|
82
|
-
Time.parse(job[:completed_at]) - Time.parse(job[:started_at])
|
|
84
|
+
[Time.parse(job[:completed_at]) - Time.parse(job[:started_at]), 0].max
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
def self.row_to_hash(row)
|
|
@@ -14,6 +14,14 @@ module FunCi
|
|
|
14
14
|
|
|
15
15
|
Commit = Data.define(:sha, :branch)
|
|
16
16
|
|
|
17
|
+
# On a detached HEAD git names no branch, and the hooks pass "": the run
|
|
18
|
+
# is kept, shown and cancelled by others on the branch "detached".
|
|
19
|
+
class Commit
|
|
20
|
+
DETACHED = "detached"
|
|
21
|
+
|
|
22
|
+
def initialize(sha:, branch:) = super(sha: sha, branch: branch.empty? ? DETACHED : branch)
|
|
23
|
+
end
|
|
24
|
+
|
|
17
25
|
Io = Data.define(:stdout, :stderr) do
|
|
18
26
|
def initialize(stdout: $stdout, stderr: $stderr) = super
|
|
19
27
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FunCi
|
|
4
|
+
module Setup
|
|
5
|
+
# The source linter a Gradle build applies, whose task lint.sh runs. Lint
|
|
6
|
+
# runs beside the build on the source alone (design.md, Stages side by
|
|
7
|
+
# side), so only linters that compile nothing are named here.
|
|
8
|
+
class GradleLinterDetector
|
|
9
|
+
LINTERS = [
|
|
10
|
+
{ plugin: "org.jlleitschuh.gradle.ktlint", command: "./gradlew ktlintCheck" },
|
|
11
|
+
{ plugin: "com.diffplug.spotless", command: "./gradlew spotlessCheck" },
|
|
12
|
+
{ plugin: "io.gitlab.arturbosch.detekt", command: "./gradlew detekt" }
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
def initialize(build_file)
|
|
16
|
+
@build_file = build_file
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The linter's command, or nil for a build that applies none.
|
|
20
|
+
def lint_command = LINTERS.find { |linter| @build_file.include?(linter[:plugin]) }&.fetch(:command)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "project_detector"
|
|
4
4
|
require_relative "template_writer"
|
|
5
|
-
require_relative "
|
|
5
|
+
require_relative "lint_detection"
|
|
6
6
|
require_relative "agent_instructions"
|
|
7
7
|
|
|
8
8
|
module FunCi
|
|
9
9
|
module Setup
|
|
10
10
|
class Installer
|
|
11
|
+
# Which stages run side by side, and so what each may touch (design.md,
|
|
12
|
+
# Stages side by side).
|
|
13
|
+
SIDE_BY_SIDE = ["lint.sh runs beside build.sh, so it reads the source alone.",
|
|
14
|
+
"Then fast.sh runs beside slow.sh, both on what build.sh built: have build.sh " \
|
|
15
|
+
"compile everything they need, test code included."].freeze
|
|
16
|
+
|
|
11
17
|
def self.run(project_root:, stdout: $stdout)
|
|
12
18
|
new(project_root: project_root, stdout: stdout).run
|
|
13
19
|
end
|
|
@@ -51,21 +57,15 @@ module FunCi
|
|
|
51
57
|
|
|
52
58
|
def write_templates(detected)
|
|
53
59
|
@stdout.puts "Detected: #{detected.to_s.tr("_", " ")}"
|
|
54
|
-
TemplateWriter.new(detected, @project_root, lint_override:
|
|
55
|
-
|
|
60
|
+
TemplateWriter.new(detected, @project_root, lint_override: LintDetection.command(detected, @project_root)).write
|
|
61
|
+
@stdout.puts "Created .fun-ci/ with template scripts.", *SIDE_BY_SIDE
|
|
62
|
+
0
|
|
56
63
|
end
|
|
57
64
|
|
|
58
65
|
def report(message, exit_code)
|
|
59
66
|
@stdout.puts message
|
|
60
67
|
exit_code
|
|
61
68
|
end
|
|
62
|
-
|
|
63
|
-
def detect_maven_linter(detected)
|
|
64
|
-
return nil unless detected == :jvm_maven
|
|
65
|
-
|
|
66
|
-
command = MavenLinterDetector.new(File.read(File.join(@project_root, "pom.xml"))).lint_command
|
|
67
|
-
command == MavenLinterDetector::DEFAULT_COMMAND ? nil : command
|
|
68
|
-
end
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "maven_linter_detector"
|
|
4
|
+
require_relative "gradle_linter_detector"
|
|
5
|
+
|
|
6
|
+
module FunCi
|
|
7
|
+
module Setup
|
|
8
|
+
# The lint command init writes in place of the template's, from the source
|
|
9
|
+
# linter the project's build configures; nil keeps the template's.
|
|
10
|
+
module LintDetection
|
|
11
|
+
GRADLE_FILES = %w[build.gradle.kts build.gradle].freeze
|
|
12
|
+
|
|
13
|
+
def self.command(detected, project_root)
|
|
14
|
+
case detected
|
|
15
|
+
when :jvm_maven then maven(project_root)
|
|
16
|
+
when :jvm_gradle_kotlin, :jvm_gradle_groovy then gradle(project_root)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.maven(project_root)
|
|
21
|
+
command = MavenLinterDetector.new(File.read(File.join(project_root, "pom.xml"))).lint_command
|
|
22
|
+
command == MavenLinterDetector::DEFAULT_COMMAND ? nil : command
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.gradle(project_root)
|
|
26
|
+
file = GRADLE_FILES.map { File.join(project_root, _1) }.find { File.exist?(_1) }
|
|
27
|
+
file && GradleLinterDetector.new(File.read(file)).lint_command
|
|
28
|
+
end
|
|
29
|
+
private_class_method :maven, :gradle
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module FunCi
|
|
4
4
|
module Setup
|
|
5
|
+
# The linter a POM configures, whose goal lint.sh runs. Lint runs beside the
|
|
6
|
+
# build on the source alone (design.md, Stages side by side), so linters that
|
|
7
|
+
# read compiled classes, such as spotbugs, are left to build.sh or fast.sh.
|
|
5
8
|
class MavenLinterDetector
|
|
6
9
|
LINTERS = [
|
|
7
10
|
{ artifact_id: "detekt-maven-plugin", command: "mvn detekt:check" },
|
|
8
11
|
{ artifact_id: "ktlint-maven-plugin", command: "mvn ktlint:check" },
|
|
9
12
|
{ artifact_id: "maven-checkstyle-plugin", command: "mvn checkstyle:check" },
|
|
10
|
-
{ artifact_id: "spotbugs-maven-plugin", command: "mvn spotbugs:check" },
|
|
11
13
|
{ artifact_id: "maven-pmd-plugin", command: "mvn pmd:check" }
|
|
12
14
|
].freeze
|
|
13
15
|
|
|
14
|
-
DEFAULT_COMMAND = "mvn
|
|
16
|
+
DEFAULT_COMMAND = "mvn validate"
|
|
15
17
|
|
|
16
18
|
def initialize(pom_content)
|
|
17
19
|
@pom_content = pom_content
|
|
@@ -6,18 +6,23 @@ module FunCi
|
|
|
6
6
|
module Setup
|
|
7
7
|
# Stacks that run on a virtual machine: the JVM, .NET, the BEAM and Dart's.
|
|
8
8
|
module StageTemplates
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
NO_GRADLE_LINTER = 'echo "No source linter in the build: put ktlint, spotless or detekt in .fun-ci/lint.sh"'
|
|
10
|
+
|
|
11
|
+
GRADLE = stages(NO_GRADLE_LINTER, "./gradlew assemble testClasses",
|
|
12
|
+
"./gradlew test", "./gradlew integrationTest").freeze
|
|
11
13
|
|
|
12
14
|
MANAGED = {
|
|
13
15
|
jvm_gradle_kotlin: GRADLE,
|
|
14
16
|
jvm_gradle_groovy: GRADLE,
|
|
15
|
-
jvm_maven: stages("mvn
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
jvm_maven: stages("mvn validate", "mvn test-compile", "mvn surefire:test",
|
|
18
|
+
"mvn failsafe:integration-test failsafe:verify"),
|
|
19
|
+
dotnet: stages("dotnet format whitespace --folder --verify-no-changes", "dotnet build",
|
|
20
|
+
'dotnet test --no-build --filter "Category!=Slow"',
|
|
21
|
+
'dotnet test --no-build --filter "Category=Slow"'),
|
|
22
|
+
elixir_mix: stages("mix format --check-formatted", "mix deps.get && MIX_ENV=test mix compile",
|
|
19
23
|
"mix test --exclude slow", "mix test --only slow"),
|
|
20
|
-
dart: stages("dart analyze", "dart pub get", "dart test --exclude-tags slow",
|
|
24
|
+
dart: stages("dart analyze", "dart pub get --precompile", "dart test --exclude-tags slow",
|
|
25
|
+
"dart test --compiler source --tags slow")
|
|
21
26
|
}.freeze
|
|
22
27
|
end
|
|
23
28
|
end
|
|
@@ -15,7 +15,7 @@ module FunCi
|
|
|
15
15
|
"cargo test", "cargo test -- --ignored"),
|
|
16
16
|
go: stages("go vet ./...", "go build ./...", "go test -short ./...", "go test ./..."),
|
|
17
17
|
swift: stages("swift format lint --recursive --strict .", "swift build --build-tests",
|
|
18
|
-
"swift test --skip Slow", "swift test --filter Slow"),
|
|
18
|
+
"swift test --skip-build --skip Slow", "swift test --skip-build --filter Slow"),
|
|
19
19
|
cmake: stages(CLANG_FORMAT, "cmake -S . -B build && cmake --build build",
|
|
20
20
|
"#{CTEST} -LE slow", "#{CTEST} -L slow"),
|
|
21
21
|
make: stages("make lint", "make", "make test", "make test-slow")
|
|
@@ -4,11 +4,20 @@ module FunCi
|
|
|
4
4
|
module Setup
|
|
5
5
|
# What every stack's stage scripts are made of.
|
|
6
6
|
module StageTemplates
|
|
7
|
-
|
|
7
|
+
# What each stage runs beside, said where its script is edited (design.md,
|
|
8
|
+
# Stages side by side).
|
|
9
|
+
SIDE_BY_SIDE = {
|
|
10
|
+
"lint.sh" => "Runs beside build.sh, so it reads the source alone.",
|
|
11
|
+
"build.sh" => "Runs beside lint.sh; then fast.sh and slow.sh run side by side on what it builds.",
|
|
12
|
+
"fast.sh" => "Runs beside slow.sh, on what build.sh built.",
|
|
13
|
+
"slow.sh" => "Runs beside fast.sh, on what build.sh built."
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
def self.script(name, body) = "#!/bin/sh\n# #{SIDE_BY_SIDE.fetch(name)}\n#{body}\n"
|
|
8
17
|
|
|
9
18
|
def self.stages(lint, build, fast, slow)
|
|
10
|
-
{ "lint.sh" => lint, "build.sh" => build, "fast.sh" => fast, "slow.sh" => slow }.
|
|
11
|
-
script(body)
|
|
19
|
+
{ "lint.sh" => lint, "build.sh" => build, "fast.sh" => fast, "slow.sh" => slow }.to_h do |name, body|
|
|
20
|
+
[name, script(name, body)]
|
|
12
21
|
end
|
|
13
22
|
end
|
|
14
23
|
end
|
|
@@ -18,7 +18,7 @@ module FunCi
|
|
|
18
18
|
# { "lint.sh" => script, ... }; +lint_override+ replaces the lint command.
|
|
19
19
|
def self.scripts(template_id, lint_override: nil)
|
|
20
20
|
scripts = TEMPLATES.fetch(template_id)
|
|
21
|
-
lint_override ? scripts.merge("lint.sh" => script(lint_override)) : scripts
|
|
21
|
+
lint_override ? scripts.merge("lint.sh" => script("lint.sh", lint_override)) : scripts
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
end
|
data/lib/fun_ci/version.rb
CHANGED
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.0.
|
|
4
|
+
version: 2.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Erik Thyge Madsen
|
|
@@ -237,10 +237,12 @@ files:
|
|
|
237
237
|
- lib/fun_ci/setup/agent_instructions.rb
|
|
238
238
|
- lib/fun_ci/setup/commands.rb
|
|
239
239
|
- lib/fun_ci/setup/git_hooks.rb
|
|
240
|
+
- lib/fun_ci/setup/gradle_linter_detector.rb
|
|
240
241
|
- lib/fun_ci/setup/hook_script.rb
|
|
241
242
|
- lib/fun_ci/setup/hook_writer.rb
|
|
242
243
|
- lib/fun_ci/setup/installer.rb
|
|
243
244
|
- lib/fun_ci/setup/legacy_hooks.rb
|
|
245
|
+
- lib/fun_ci/setup/lint_detection.rb
|
|
244
246
|
- lib/fun_ci/setup/maven_linter_detector.rb
|
|
245
247
|
- lib/fun_ci/setup/project_config.rb
|
|
246
248
|
- lib/fun_ci/setup/project_detector.rb
|