Skip to content

Commit

Permalink
feat: add ruby stack first implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
joao10lima committed Nov 9, 2021
1 parent 72815fe commit 7e4f458
Show file tree
Hide file tree
Showing 14 changed files with 415 additions and 0 deletions.
38 changes: 38 additions & 0 deletions cli/tests/default_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,41 @@ test(
await cleanGitHubFiles("python/setup-flake8");
},
);

test(
{ fixture: "python/setup-flake8", args: ["--no-strict"] },
async (proc) => {
const [stdout, _stderr, { code }] = await output(proc);
assertStringIncludes(stdout, "Detected stack: python");
assertStringIncludes(
stdout,
"Couldn't detect the Python version, using the latest available: 3.10",
);
assertStringIncludes(
stdout,
"No linters for python were identified in the project, creating default pipeline with 'flake8' WITHOUT any specific configuration",
);
assertStringIncludes(
stdout,
"No formatters for python were identified in the project, creating default pipeline with 'black' WITHOUT any specific configuration",
);
assertStringIncludes(
stdout,
"No formatters for python were identified in the project, creating default pipeline with 'isort' WITHOUT any specific configuration",
);
assertEquals(code, 0);
await assertExpectedFiles("python/setup-flake8");
await cleanGitHubFiles("python/setup-flake8");
},
);

test(
{ fixture: "ruby/rubocop-lint", args: ["--no-strict"] },
async (proc) => {
const [stdout, _stderr, { code }] = await output(proc);
assertStringIncludes(stdout, "Detected stack: ruby");
assertEquals(code, 0);
await assertExpectedFiles("ruby/rubocop-lint");
await cleanGitHubFiles("ruby/rubocop-lint");
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated with pipelinit 0.2.0
# https://pipelinit.com/
name: Lint Ruby
on:
pull_request:
paths:
- "**.rb"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "2.5.0"
bundler-cache: true
- run: bundle exec rubocop --lint .
5 changes: 5 additions & 0 deletions cli/tests/fixtures/ruby/rubocop-lint/project/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source "https://rubygems.org"

gemspec

gem 'rubocop', '~> 0.57.2', require: false
39 changes: 39 additions & 0 deletions cli/tests/fixtures/ruby/rubocop-lint/project/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
PATH
remote: .
specs:
main (0.3.1)

GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
jaro_winkler (1.5.4)
parallel (1.21.0)
parser (3.0.2.0)
ast (~> 2.4.1)
powerpack (0.1.3)
rainbow (2.2.2)
rake
rake (10.5.0)
rubocop (0.57.2)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.5)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.11.0)
unicode-display_width (1.8.0)

PLATFORMS
ruby
x86_64-linux

DEPENDENCIES
bundler (>= 1.16)
main!
rubocop (~> 0.57.2)

BUNDLED WITH
2.2.30
1 change: 1 addition & 0 deletions cli/tests/fixtures/ruby/rubocop-lint/project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# test-ruby-pipelinit
6 changes: 6 additions & 0 deletions cli/tests/fixtures/ruby/rubocop-lint/project/lib/main.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require 'main/version'
require 'main/hash'
require 'main/script'
require 'main/report'
require 'main/config'
require 'main/cli'
15 changes: 15 additions & 0 deletions cli/tests/fixtures/ruby/rubocop-lint/project/main.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

Gem::Specification.new do |spec|
spec.name = 'main'
spec.version = '0.3.1'
spec.author = 'pipelinit'

spec.required_ruby_version = '>= 2.5.0'

spec.summary = 'Aplicação para gerar'
spec.description = 'Aplicação para gerar'

spec.add_development_dependency 'bundler', '>= 1.16'
spec.add_development_dependency 'rubocop', '~> 1.22'
end
5 changes: 5 additions & 0 deletions core/plugins/stack/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { introspector as HtmlIntrospector } from "./html/mod.ts";
import { introspector as JavaIntrospector } from "./java/mod.ts";
import { introspector as JavaScriptIntrospector } from "./javascript/mod.ts";
import { introspector as PythonIntrospector } from "./python/mod.ts";
import { introspector as RubyIntrospector } from "./ruby/mod.ts";
import { introspector as ShellIntrospector } from "./shell/mod.ts";

import type CSSProject from "./css/mod.ts";
Expand All @@ -12,6 +13,7 @@ import type HtmlProject from "./html/mod.ts";
import type JavaScriptProject from "./javascript/mod.ts";
import type JavaProject from "./java/mod.ts";
import type PythonProject from "./python/mod.ts";
import type RubyProject from "./ruby/mod.ts";
import type ShellProject from "./shell/mod.ts";

// Keep it in alphabetical order
Expand All @@ -22,6 +24,7 @@ export type ProjectData =
| JavaScriptProject
| JavaProject
| PythonProject
| RubyProject
| ShellProject;

export type {
Expand All @@ -31,6 +34,7 @@ export type {
JavaProject,
JavaScriptProject,
PythonProject,
RubyProject,
ShellProject,
};

Expand All @@ -41,5 +45,6 @@ export const introspectors = [
{ name: "javascript", ...JavaScriptIntrospector },
{ name: "java", ...JavaIntrospector },
{ name: "python", ...PythonIntrospector },
{ name: "ruby", ...RubyIntrospector },
{ name: "shell", ...ShellIntrospector },
];
31 changes: 31 additions & 0 deletions core/plugins/stack/ruby/dependencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Context } from "../../../types.ts";

const rubyDepRegex = /(?:(["'])(?<DependencyName>[a-zA-Z\-_\.]+)["'])/gm;

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
return value !== null && value !== undefined;
}

const readDependencyFile = async (context: Context) => {
for await (const file of await context.files.each("**/Gemfile")) {
const rubyDepsText = await context.files.readText(file.path);

const depsRuby: string[] = Array.from(
rubyDepsText.matchAll(rubyDepRegex),
(match) => !match.groups ? null : match.groups.DependencyName,
).filter(notEmpty);

if (depsRuby) {
return depsRuby;
}
}
return [];
};

export const hasRubyDependency = async (
context: Context,
dependencyName: string,
): Promise<boolean> => {
const dependencies = await readDependencyFile(context);
return dependencies.some((dep) => dep === dependencyName);
};
29 changes: 29 additions & 0 deletions core/plugins/stack/ruby/linters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { IntrospectFn } from "../../../types.ts";
import { introspect as introspectRubocop, Rubocop } from "./rubocop.ts";

export type Linters = {
rubocop?: Rubocop;
};

export const introspect: IntrospectFn<Linters> = async (context) => {
const linters: Linters = {};
const logger = context.getLogger("ruby");

const rubocopInfo = await introspectRubocop(context);
if (rubocopInfo) {
logger.debug("detected Rubocop");
linters.rubocop = rubocopInfo;
} else {
if (context.suggestDefault) {
logger.warning(
"No linters for ruby were identified in the project, creating default pipeline with 'Rubocop' WITHOUT any specific configuration",
);
linters.rubocop = {
isDependency: false,
name: "rubocop",
};
}
}

return linters;
};
43 changes: 43 additions & 0 deletions core/plugins/stack/ruby/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Introspector } from "../../../types.ts";
import { introspect as introspectVersion } from "./version.ts";
import { introspect as introspectLinters, Linters } from "./linters.ts";

/**
* Introspected information about a project with Ruby
*/
export default interface RubyProject {
/**
* Ruby version
*/
version?: string;
/**
* Which linter the project uses, if any
*/
linters: Linters;
}

export const introspector: Introspector<RubyProject | undefined> = {
detect: async (context) => {
return await context.files.includes("**/*.rb");
},
introspect: async (context) => {
const logger = context.getLogger("ruby");

// Version
logger.debug("detecting version");
const version = await introspectVersion(context);
if (version === undefined) {
logger.debug("didn't detect the version");
return undefined;
}
logger.debug(`detected version ${version}`);

// Linters and Formatters
const linters = await introspectLinters(context);

return {
version: version,
linters: linters,
};
},
};
31 changes: 31 additions & 0 deletions core/plugins/stack/ruby/rubocop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { IntrospectFn } from "../../../types.ts";
import { hasRubyDependency } from "./dependencies.ts";

export interface Rubocop {
name: "rubocop";
isDependency: boolean;
}

export const introspect: IntrospectFn<Rubocop | null> = async (context) => {
const isDependency = await hasRubyDependency(context, "rubocop");
// Search for any of the following files:
// .rubocop.yml
// Reference: https://docs.rubocop.org/rubocop/configuration.html#config-file-locations
const hasRubocopConfig = await context.files.includes(
"**/.rubocop.yml",
);

if (hasRubocopConfig) {
return {
name: "rubocop",
isDependency: isDependency,
};
} else if (isDependency) {
return {
name: "rubocop",
isDependency: true,
};
}

return null;
};

0 comments on commit 7e4f458

Please sign in to comment.