veragem 0.1.0 → 0.2.0
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 +230 -34
- data/Gemfile.lock +254 -0
- data/README.md +143 -48
- data/lib/veragem/citation.rb +116 -0
- data/lib/veragem/generator.rb +105 -56
- data/lib/veragem/license.rb +27 -0
- data/lib/veragem/name.rb +110 -48
- data/lib/veragem/options.rb +116 -30
- data/lib/veragem/project.rb +200 -39
- data/lib/veragem/questions.rb +163 -0
- data/lib/veragem/summary.rb +62 -0
- data/lib/veragem/version.rb +2 -1
- data/lib/veragem.rb +12 -3
- data/plugins.rb +4 -0
- data/sig/veragem.rbs +151 -23
- data/template/.gitattributes +3 -0
- data/template/.githooks/pre-commit +2 -3
- data/template/.github/PULL_REQUEST_TEMPLATE.md +2 -1
- data/template/.github/dependabot.yml +4 -8
- data/template/.github/image-registries.sh +4 -3
- data/template/.github/workflows/dependabot-automerge.yml +29 -34
- data/template/.github/workflows/dependency-review.yml +19 -15
- data/template/.github/workflows/image.yml +65 -14
- data/template/.github/workflows/links.yml +35 -0
- data/template/.github/workflows/nix.yml +3 -3
- data/template/.github/workflows/release.yml +135 -22
- data/template/.github/workflows/ruby-ci.yml +31 -9
- data/template/.github/workflows/security.yml +15 -9
- data/template/.github/workflows/style-check-cocogitto.yml +3 -4
- data/template/.github/workflows/style-check-dprint.yml +10 -10
- data/template/.gitignore +5 -0
- data/template/.mutineer.yml +28 -0
- data/template/.rubocop.yml +49 -10
- data/template/.simplecov.erb +10 -0
- data/template/.yard-lint.yml +386 -0
- data/template/.yardopts +2 -0
- data/template/AGENTS.md.erb +76 -38
- data/template/CITATION.cff.erb +50 -0
- data/template/CODE_OF_CONDUCT.md.erb +1 -1
- data/template/CONTRIBUTING.md.erb +107 -48
- data/template/Gemfile +10 -7
- data/template/README.md.erb +12 -12
- data/template/Rakefile +167 -31
- data/template/Steepfile.erb +1 -1
- data/template/bin/setup +2 -0
- data/template/cliff.toml +40 -23
- data/template/dprint.json +1 -6
- data/template/flake.lock +3 -3
- data/template/flake.nix +25 -10
- data/template/lib/%path%/cli.rb.erb +19 -15
- data/template/lib/%path%/version.rb.erb +1 -1
- data/template/lib/%path%.rb.erb +3 -1
- data/template/sig/%path%.rbs.erb +1 -1
- data/template/test/test_%underscored%.rb.erb +4 -3
- data/template/test/test_cli.rb.erb +37 -12
- data/template/test/test_helper.rb.erb +15 -7
- metadata +16 -4
- data/template/.github/workflows/rubocop-autocorrect.yml +0 -114
data/template/Steepfile.erb
CHANGED
data/template/bin/setup
CHANGED
|
@@ -3,3 +3,5 @@
|
|
|
3
3
|
|
|
4
4
|
# The gems at Gemfile.lock's versions; the first run writes the lock, to commit.
|
|
5
5
|
system("bundle", "install", exception: true)
|
|
6
|
+
# Windows' gems too, as CI checks the gem there and installs from the lock alone
|
|
7
|
+
system("bundle", "lock", "--add-platform", "x64-mingw-ucrt", exception: true)
|
data/template/cliff.toml
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
# git-cliff: CHANGELOG.md from the Conventional Commits, written by `rake bump` (never by hand).
|
|
2
|
-
# Grouped by commit type, breaking changes first; what changes nothing a user meets (chores, CI,
|
|
3
|
-
# formatting, the release commit itself) is left out.
|
|
4
2
|
#
|
|
5
|
-
# It names no project: the Rakefile passes the repository the
|
|
6
|
-
#
|
|
3
|
+
# It names no project: the Rakefile passes the repository the links need (`--github-repo`, from
|
|
4
|
+
# the gemspec's source_code_uri). Run bare, it takes the current branch's upstream remote where that
|
|
5
|
+
# is GitHub's, and writes no link otherwise.
|
|
7
6
|
|
|
8
7
|
[changelog]
|
|
9
8
|
header = """
|
|
@@ -33,8 +32,11 @@ body = """
|
|
|
33
32
|
{% for group, commits in commits | group_by(attribute="group") %}
|
|
34
33
|
### {{ group | striptags | trim }}
|
|
35
34
|
{% for commit in commits %}
|
|
35
|
+
{# the description as its author wrote it: a name keeps its case (RuboCop, v0.1.0) -#}
|
|
36
|
+
{% set short = commit.id | truncate(length=7, end="") -%}
|
|
36
37
|
- {% if commit.scope %}{{ commit.scope }}: {% endif %}\
|
|
37
|
-
{{ commit.message | split(pat="\n") | first |
|
|
38
|
+
{{ commit.message | split(pat="\n") | first | trim }} \
|
|
39
|
+
({% if url %}[{{ short }}]({{ url }}/commit/{{ commit.id }}){% else %}{{ short }}{% endif %})\
|
|
38
40
|
{% endfor %}
|
|
39
41
|
{% endfor %}\n
|
|
40
42
|
"""
|
|
@@ -42,28 +44,43 @@ trim = true
|
|
|
42
44
|
|
|
43
45
|
[git]
|
|
44
46
|
conventional_commits = true
|
|
45
|
-
|
|
46
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
commit_preprocessors = [
|
|
48
|
+
# a body right under its subject, which cog takes, set apart as git-cliff's parser needs it:
|
|
49
|
+
# its footers (BREAKING CHANGE) read
|
|
50
|
+
{ pattern = '\A([^\n]*)\n([^\n])', replace = "${1}\n\n${2}" },
|
|
51
|
+
# GitHub's markers that skip a commit's workflows, at a line's end: no changelog text
|
|
52
|
+
{ pattern = '(?m)( *\[(skip ci|ci skip|no ci|skip actions|actions skip)\])+ *$', replace = "" },
|
|
53
|
+
]
|
|
54
|
+
# every commit to the parsers, then an unconventional one they keep fails the changelog: cog lets
|
|
55
|
+
# through merges and fixups alone, which they skip (one that got past cog anyway: its SHA in
|
|
56
|
+
# .cliffignore, which git-cliff skips). Filtered before the parsers instead, a merge warns as a
|
|
57
|
+
# parse error
|
|
58
|
+
require_conventional = true
|
|
50
59
|
protect_breaking_commits = true # a breaking change is listed whatever its type, first
|
|
51
|
-
# by type, in any case (cog takes `Feat:`)
|
|
60
|
+
# every conventional commit, by type, in any case (cog takes `Feat:`); the HTML comments order the
|
|
61
|
+
# groups, two digits as they sort as text
|
|
52
62
|
commit_parsers = [
|
|
53
63
|
# a merge, whatever its message: cog checks none (ignore_merge_commits)
|
|
54
64
|
{ field = "merge_commit", pattern = "true", skip = true },
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
{ message = "(
|
|
60
|
-
{ message = "(
|
|
61
|
-
{
|
|
62
|
-
{ message = "(?i)^
|
|
63
|
-
{ message = "(?i)^
|
|
64
|
-
{ message = "(?i)^
|
|
65
|
-
{ message = "(?i)^
|
|
66
|
-
{ message = "
|
|
65
|
+
# what else cog lets through unconventional (ignore_fixup_commits)
|
|
66
|
+
{ message = "^(fixup|squash|amend)!", skip = true },
|
|
67
|
+
# the release commit (`rake bump`'s), tagged: in its own section, which a later bump would
|
|
68
|
+
# rewrite once published
|
|
69
|
+
{ message = "^chore\\(release\\): ", skip = true },
|
|
70
|
+
{ message = "^[a-zA-Z]+(\\([^)]*\\))?!:", group = "<!-- 00 -->Breaking changes" },
|
|
71
|
+
{ footer = "^BREAKING[ -]CHANGE", group = "<!-- 00 -->Breaking changes" },
|
|
72
|
+
{ message = "(?i)^feat", group = "<!-- 01 -->Features" },
|
|
73
|
+
{ message = "(?i)^fix", group = "<!-- 02 -->Fixes" },
|
|
74
|
+
{ message = "(?i)^perf", group = "<!-- 03 -->Performance" },
|
|
75
|
+
{ message = "(?i)^refactor", group = "<!-- 04 -->Refactoring" },
|
|
76
|
+
{ message = "(?i)^build", group = "<!-- 05 -->Build" },
|
|
77
|
+
{ message = "(?i)^doc", group = "<!-- 06 -->Documentation" },
|
|
78
|
+
{ message = "(?i)^test", group = "<!-- 07 -->Tests" },
|
|
79
|
+
{ message = "(?i)^revert", group = "<!-- 08 -->Reverts" },
|
|
80
|
+
{ message = "(?i)^style", group = "<!-- 09 -->Styling" },
|
|
81
|
+
{ message = "(?i)^(chore|ci)", group = "<!-- 10 -->Miscellaneous Tasks" },
|
|
82
|
+
# any other type cog takes
|
|
83
|
+
{ message = ".*", group = "<!-- 11 -->Other" },
|
|
67
84
|
]
|
|
68
85
|
sort_commits = "oldest"
|
|
69
86
|
# the release tags, `v0.1.0` on (Bundler's own form, `rake release`)
|
data/template/dprint.json
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
// Markdown and TOML (`rake dprint`, style-check-dprint.yml). The plugins pinned:
|
|
2
|
-
// `dprint config update` moves them to their latest.
|
|
3
1
|
{
|
|
4
2
|
"markdown": {
|
|
5
3
|
"textWrap": "maintain",
|
|
6
|
-
// the plugin's defaults are underscores
|
|
7
4
|
"emphasisKind": "asterisks",
|
|
8
5
|
"strongKind": "asterisks"
|
|
9
6
|
},
|
|
10
|
-
// four spaces, as cliff.toml and cog.toml are written
|
|
11
7
|
"toml": { "indentWidth": 4 },
|
|
12
8
|
"excludes": [
|
|
13
|
-
// git-cliff's (cliff.toml): regenerated at each release, never edited
|
|
14
9
|
"CHANGELOG.md",
|
|
15
10
|
"coverage/",
|
|
16
11
|
"pkg/",
|
|
17
12
|
"vendor/"
|
|
18
13
|
],
|
|
19
14
|
"plugins": [
|
|
20
|
-
"https://plugins.dprint.dev/markdown-0.
|
|
15
|
+
"https://plugins.dprint.dev/markdown-0.28.2.wasm",
|
|
21
16
|
"https://plugins.dprint.dev/toml-0.9.0.wasm"
|
|
22
17
|
]
|
|
23
18
|
}
|
data/template/flake.lock
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"nodes": {
|
|
3
3
|
"nixpkgs": {
|
|
4
4
|
"locked": {
|
|
5
|
-
"lastModified":
|
|
6
|
-
"narHash": "sha256-
|
|
5
|
+
"lastModified": 1793540411,
|
|
6
|
+
"narHash": "sha256-fiPJ88izTVucjeo2EQ3jk4aWmLg03I1D4vxnX2QjEgE=",
|
|
7
7
|
"owner": "NixOS",
|
|
8
8
|
"repo": "nixpkgs",
|
|
9
|
-
"rev": "
|
|
9
|
+
"rev": "0bb2eedc20e4739f29e8045034f2828ad7054f8f",
|
|
10
10
|
"type": "github"
|
|
11
11
|
},
|
|
12
12
|
"original": {
|
data/template/flake.nix
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# The development shell, the gem as a package, and the checks that need no gem from the bundle:
|
|
2
2
|
#
|
|
3
|
-
# nix develop Ruby 4.0 and every tool
|
|
3
|
+
# nix develop Ruby 4.0 and every tool the Rakefile runs besides the gems (Bundler's, from
|
|
4
4
|
# Gemfile.lock: `bin/setup`): cocogitto, git-cliff, dprint, shellcheck, shfmt,
|
|
5
|
-
# actionlint, zizmor, nixfmt
|
|
5
|
+
# actionlint, zizmor, nixfmt, lychee
|
|
6
6
|
# nix build the gem, built from its gemspec and installed (nixpkgs' buildRubyGem);
|
|
7
7
|
# with a command (exe/<name>): `nix run` runs it, and on Linux
|
|
8
8
|
# `nix build .#image` builds it as an OCI image (image.yml publishes it)
|
|
9
9
|
# nix fmt the Nix, by nixfmt
|
|
10
10
|
# nix flake check the Nix format, the shell scripts (shellcheck, shfmt), the workflows
|
|
11
11
|
# (actionlint, zizmor), the package and its library loaded -- and the command
|
|
12
|
-
# run, and its image --
|
|
12
|
+
# run, and its image built -- and CITATION.cff where there is one (cffconvert);
|
|
13
|
+
# offline in the sandbox: git's files alone
|
|
13
14
|
#
|
|
14
15
|
# Nothing here names the gem: its name is the gemspec's file; its version, lib/<path>/version.rb's
|
|
15
16
|
# VERSION; its summary, homepage and licences, the gemspec's lines that set them.
|
|
@@ -36,7 +37,9 @@
|
|
|
36
37
|
if lib.length gemspecs == 1 then
|
|
37
38
|
lib.removeSuffix ".gemspec" (lib.head gemspecs)
|
|
38
39
|
else
|
|
39
|
-
throw "flake.nix: one *.gemspec expected, found ${
|
|
40
|
+
throw "flake.nix: one *.gemspec expected, found ${
|
|
41
|
+
if gemspecs == [ ] then "none" else toString gemspecs
|
|
42
|
+
}";
|
|
40
43
|
path = lib.replaceStrings [ "-" ] [ "/" ] name;
|
|
41
44
|
# the groups of the first of +file+'s lines that +pattern+ matches whole, or null
|
|
42
45
|
line =
|
|
@@ -60,7 +63,7 @@
|
|
|
60
63
|
found = line ''[[:space:]]*VERSION[[:space:]]*=[[:space:]]*"([^"]+)"${rest}'' ./lib/${path}/version.rb;
|
|
61
64
|
in
|
|
62
65
|
if found == null then
|
|
63
|
-
throw "flake.nix: no VERSION = \"...\" line in version.rb"
|
|
66
|
+
throw "flake.nix: no VERSION = \"...\" line in lib/${path}/version.rb"
|
|
64
67
|
else
|
|
65
68
|
lib.head found;
|
|
66
69
|
# the SPDX identifiers of `spec.licenses = [...]` or `spec.license = "..."`
|
|
@@ -73,6 +76,7 @@
|
|
|
73
76
|
else
|
|
74
77
|
lib.concatLists (lib.filter lib.isList (builtins.split ''"([^"]*)"'' (lib.head found)));
|
|
75
78
|
command = builtins.pathExists ./exe/${name};
|
|
79
|
+
citation = builtins.pathExists ./CITATION.cff;
|
|
76
80
|
|
|
77
81
|
check =
|
|
78
82
|
pkgs: checkName: tools: script:
|
|
@@ -91,6 +95,9 @@
|
|
|
91
95
|
dependencies = [ ];
|
|
92
96
|
package = pkgs.buildRubyGem {
|
|
93
97
|
gemName = name;
|
|
98
|
+
# the root's: unset, buildRubyGem builds the first *.gemspec `find` lists, a test's
|
|
99
|
+
# fixture too
|
|
100
|
+
gemspec = "${name}.gemspec";
|
|
94
101
|
inherit version ruby;
|
|
95
102
|
src = self;
|
|
96
103
|
gemPath = dependencies;
|
|
@@ -141,15 +148,17 @@
|
|
|
141
148
|
|
|
142
149
|
checks = {
|
|
143
150
|
format = check pkgs "format" [ pkgs.nixfmt ] "find . -name '*.nix' -exec nixfmt --check {} +";
|
|
144
|
-
# shfmt finds the scripts, by extension or shebang, and
|
|
151
|
+
# shfmt finds the scripts, by extension or shebang, and checks them per .editorconfig
|
|
145
152
|
shell = check pkgs "shell" [ pkgs.shellcheck pkgs.shfmt ] ''
|
|
146
|
-
shfmt --find . | xargs shellcheck
|
|
153
|
+
shfmt --find . | xargs -d '\n' shellcheck
|
|
147
154
|
shfmt --diff .
|
|
148
155
|
'';
|
|
149
156
|
# actionlint runs shellcheck on each `run:` script too; zizmor audits Dependabot's
|
|
150
|
-
# configuration as well
|
|
157
|
+
# configuration as well. The workflows named: actionlint finds them in a git repository
|
|
158
|
+
# alone, and the sandbox has none
|
|
151
159
|
workflows = check pkgs "workflows" [ pkgs.actionlint pkgs.shellcheck pkgs.zizmor ] ''
|
|
152
|
-
|
|
160
|
+
shopt -s nullglob
|
|
161
|
+
actionlint .github/workflows/*.{yml,yaml}
|
|
153
162
|
zizmor --offline --quiet --strict-collection .
|
|
154
163
|
'';
|
|
155
164
|
inherit package;
|
|
@@ -186,6 +195,10 @@
|
|
|
186
195
|
touch $out
|
|
187
196
|
'';
|
|
188
197
|
}
|
|
198
|
+
// lib.optionalAttrs citation {
|
|
199
|
+
# CFF's schema alone: Zenodo's import refuses more, which the generator never writes
|
|
200
|
+
citation = check pkgs "citation" [ pkgs.cffconvert ] "cffconvert --validate -i CITATION.cff";
|
|
201
|
+
}
|
|
189
202
|
// lib.optionalAttrs linuxCommand { inherit image; };
|
|
190
203
|
|
|
191
204
|
devShells.default = pkgs.mkShell {
|
|
@@ -199,10 +212,12 @@
|
|
|
199
212
|
pkgs.actionlint
|
|
200
213
|
pkgs.zizmor
|
|
201
214
|
pkgs.nixfmt
|
|
215
|
+
pkgs.lychee
|
|
202
216
|
];
|
|
203
217
|
};
|
|
204
218
|
};
|
|
205
|
-
|
|
219
|
+
all = forAllSystems perSystem;
|
|
220
|
+
output = attribute: lib.mapAttrs (_: outputs: outputs.${attribute}) all;
|
|
206
221
|
in
|
|
207
222
|
{
|
|
208
223
|
packages = output "packages";
|
|
@@ -3,43 +3,47 @@
|
|
|
3
3
|
require "optparse"
|
|
4
4
|
require_relative "../<%= File.basename(path) %>"
|
|
5
5
|
|
|
6
|
+
<%# `::` where one of the gem's modules is named OptionParser, which its lookup would find first -%>
|
|
7
|
+
<%- option_parser = "#{"::" if modules.include?("OptionParser")}OptionParser" -%>
|
|
6
8
|
<%= nest(<<~RUBY)
|
|
7
|
-
# The command line
|
|
9
|
+
# The command line, `#{name} [options] [NAME]`:
|
|
10
|
+
# it greets NAME, or prints the help or the version.
|
|
8
11
|
module CLI
|
|
9
|
-
# Runs the command line with +argv
|
|
12
|
+
# Runs the command line with +argv+.
|
|
13
|
+
# @param argv [Array<String>] the command's arguments
|
|
14
|
+
# @return [Integer] the exit status: 0, or 2 for an option refused, or more than one name
|
|
10
15
|
def self.run(argv)
|
|
11
16
|
options = { help: false, version: false }
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
name, *others = parser.parse(argv, into: options)
|
|
18
|
+
raise #{option_parser}::NeedlessArgument.new(*others) unless others.empty?
|
|
19
|
+
|
|
20
|
+
puts output(options, name.to_s)
|
|
14
21
|
0
|
|
15
|
-
rescue ::
|
|
16
|
-
warn e
|
|
22
|
+
rescue #{option_parser}::ParseError => e
|
|
23
|
+
warn "#{name}: \#{e}", parser
|
|
17
24
|
2
|
|
18
25
|
end
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
def self.output(options, name)
|
|
27
|
+
private_class_method def self.output(options, name)
|
|
22
28
|
if options[:help]
|
|
23
|
-
parser
|
|
29
|
+
parser
|
|
24
30
|
elsif options[:version]
|
|
25
31
|
parser.ver
|
|
26
32
|
else
|
|
27
33
|
#{modules.last}.greeting(name)
|
|
28
34
|
end
|
|
29
35
|
end
|
|
30
|
-
private_class_method :output
|
|
31
36
|
|
|
32
|
-
# --help as
|
|
33
|
-
#
|
|
34
|
-
def self.parser
|
|
35
|
-
|
|
37
|
+
# --help and --version as options of their own: OptionParser's own exit the process, as its
|
|
38
|
+
# shell completion still does (--*-completion-bash=WORD).
|
|
39
|
+
private_class_method def self.parser
|
|
40
|
+
#{option_parser}.new("Usage: #{name} [options] [NAME]") do |opts|
|
|
36
41
|
opts.program_name = "#{name}"
|
|
37
42
|
opts.version = VERSION
|
|
38
43
|
opts.on("-h", "--help", "Print this help")
|
|
39
44
|
opts.on("--version", "Print the version")
|
|
40
45
|
end
|
|
41
46
|
end
|
|
42
|
-
private_class_method :parser
|
|
43
47
|
end
|
|
44
48
|
RUBY
|
|
45
49
|
-%>
|
data/template/lib/%path%.rb.erb
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
require_relative "<%= File.basename(path) %>/version"
|
|
4
4
|
|
|
5
5
|
<%= nest(<<~RUBY, doc: summary)
|
|
6
|
-
# A greeting for +name+, its surrounding whitespace stripped; nobody named, the world.
|
|
6
|
+
# A greeting for +name+, its surrounding ASCII whitespace stripped; nobody named, the world.
|
|
7
|
+
# @param name [String] who to greet, "" for nobody
|
|
8
|
+
# @return [String]
|
|
7
9
|
def self.greeting(name)
|
|
8
10
|
who = name.strip
|
|
9
11
|
who = "world" if who.empty?
|
data/template/sig/%path%.rbs.erb
CHANGED
|
@@ -8,7 +8,7 @@ RBS
|
|
|
8
8
|
module CLI
|
|
9
9
|
def self.run: (::Array[::String] argv) -> ::Integer
|
|
10
10
|
|
|
11
|
-
private def self.output: (::Hash[::Symbol, bool] options, ::String name) -> ::String?
|
|
11
|
+
private def self.output: (::Hash[::Symbol, bool] options, ::String name) -> (::OptionParser | ::String)?
|
|
12
12
|
|
|
13
13
|
private def self.parser: () -> ::OptionParser
|
|
14
14
|
end
|
|
@@ -15,12 +15,13 @@ class Test<%= constant.delete(":") %> < Minitest::Test
|
|
|
15
15
|
assert_equal "Hello, world!", <%= constant %>.greeting(" \n")
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
# A property, checked on many generated names
|
|
18
|
+
# A property, checked on many generated names and whitespace around them (pbt).
|
|
19
19
|
def test_surrounding_whitespace_changes_nothing
|
|
20
20
|
gem = <%= constant %>
|
|
21
|
+
whitespace = Pbt.array(Pbt.one_of(*" \t\n\v\f\r".chars))
|
|
21
22
|
Pbt.assert do
|
|
22
|
-
Pbt.property(Pbt.printable_string) do |name|
|
|
23
|
-
assert_equal gem.greeting(name), gem.greeting("
|
|
23
|
+
Pbt.property(Pbt.printable_string, whitespace, whitespace) do |name, before, after|
|
|
24
|
+
assert_equal gem.greeting(name), gem.greeting("#{before.join}#{name}#{after.join}")
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
end
|
|
@@ -4,7 +4,6 @@ require "test_helper"
|
|
|
4
4
|
require "<%= path %>/cli"
|
|
5
5
|
|
|
6
6
|
class Test<%= constant.delete(":") %>CLI < Minitest::Test
|
|
7
|
-
# no module of the gem's can be named so: its names have no `_`
|
|
8
7
|
COMMAND_LINE = <%= constant %>::CLI
|
|
9
8
|
|
|
10
9
|
def test_it_greets_the_name_given
|
|
@@ -15,26 +14,52 @@ class Test<%= constant.delete(":") %>CLI < Minitest::Test
|
|
|
15
14
|
assert_output("Hello, world!\n") { assert_equal 0, COMMAND_LINE.run([]) }
|
|
16
15
|
end
|
|
17
16
|
|
|
18
|
-
def
|
|
17
|
+
def test_it_prints_its_version
|
|
19
18
|
expected = "<%= name %> #{<%= constant %>::VERSION}\n"
|
|
20
|
-
assert_output(expected) { assert_equal 0,
|
|
19
|
+
assert_output(expected) { assert_equal 0, command("--version") }
|
|
21
20
|
end
|
|
22
21
|
|
|
23
|
-
def
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
def test_it_prints_its_help
|
|
23
|
+
help = <<~HELP
|
|
24
|
+
Usage: <%= name %> [options] [NAME]
|
|
25
|
+
-h, --help Print this help
|
|
26
|
+
--version Print the version
|
|
27
|
+
HELP
|
|
28
|
+
%w[-h --help].each { |option| assert_output(help) { assert_equal 0, command(option) } }
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def test_an_unknown_option_is_refused
|
|
30
|
-
assert_output("",
|
|
32
|
+
assert_output("", /\A<%= name %>: invalid option: --nope\nUsage: /) do
|
|
33
|
+
assert_equal 2, COMMAND_LINE.run(["--nope"])
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_more_than_one_name_is_refused
|
|
38
|
+
assert_output("", /\A<%= name %>: needless argument: Bob\n/) do
|
|
39
|
+
assert_equal 2, COMMAND_LINE.run(%w[Ada Bob])
|
|
40
|
+
end
|
|
31
41
|
end
|
|
32
42
|
|
|
33
|
-
def
|
|
34
|
-
|
|
43
|
+
def test_the_executable_runs_it_and_exits_with_its_status
|
|
44
|
+
assert_equal ["Hello, Ada!\n", 0], executable("Ada")
|
|
45
|
+
assert_equal 2, executable("--nope").last
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# exe/<%= name %>'s output, and its exit status
|
|
51
|
+
def executable(*argv)
|
|
52
|
+
exe = File.expand_path("../exe/<%= name %>", __dir__)
|
|
35
53
|
lib = File.expand_path("../lib", __dir__)
|
|
36
|
-
out, = capture_subprocess_io { system(RbConfig.ruby, "-I", lib,
|
|
54
|
+
out, = capture_subprocess_io { system(RbConfig.ruby, "-I", lib, exe, *argv) }
|
|
55
|
+
[out, Process.last_status.exitstatus]
|
|
56
|
+
end
|
|
37
57
|
|
|
38
|
-
|
|
58
|
+
# OptionParser's own --help and --version print as these do, then exit the process: the command
|
|
59
|
+
# returns its status instead
|
|
60
|
+
def command(option)
|
|
61
|
+
COMMAND_LINE.run([option])
|
|
62
|
+
rescue SystemExit
|
|
63
|
+
flunk "#{option} exited the process"
|
|
39
64
|
end
|
|
40
65
|
end
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
# A warning Ruby reports from lib/ or the tests raises, failing the test, or the run when they load;
|
|
4
|
+
# a gem's only prints. Every category is on: `ruby -w` turns on the deprecations alone.
|
|
5
|
+
ours = [File.expand_path("../lib", __dir__), __dir__].map { "#{it}/" }
|
|
6
|
+
# Anonymous: a constant would be the module of a gem named for it (own_warnings' OwnWarnings)
|
|
7
|
+
own_warnings = Module.new do
|
|
8
|
+
define_method(:warn) do |message, **options|
|
|
9
|
+
# "PATH:LINE: ..." or, evaluated code's, "(eval at PATH:LINE):LINE: ..."; PATH relative or
|
|
10
|
+
# absolute (Windows': C:/...)
|
|
11
|
+
path = message[/\A(?:\(eval at )*(.+?):\d+[:)]/, 1]
|
|
12
|
+
raise message if path && File.expand_path(path).start_with?(*ours)
|
|
13
|
+
|
|
14
|
+
super(message, **options)
|
|
15
|
+
end
|
|
10
16
|
end
|
|
17
|
+
Warning.singleton_class.prepend(own_warnings)
|
|
18
|
+
Warning.categories.each { Warning[it] = true }
|
|
11
19
|
|
|
12
20
|
require "<%= path %>"
|
|
13
21
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: veragem
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- veralvx
|
|
@@ -11,27 +11,34 @@ date: 1980-01-02 00:00:00.000000000 Z
|
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: 'A Bundler plugin that generates a Ruby 4.0+ gem with what `bundle gem`
|
|
13
13
|
gives and the rest: Steep and TypeProf, RuboCop and its extensions, Minitest with
|
|
14
|
-
a 100% coverage gate
|
|
15
|
-
generated changelog, a Nix flake, and a release
|
|
14
|
+
a 100% coverage gate, property tests and mutation testing, YARD held by yard-lint,
|
|
15
|
+
bundler-audit, Conventional Commits, a generated changelog, a Nix flake, and a release
|
|
16
|
+
by Trusted Publishing.'
|
|
16
17
|
executables: []
|
|
17
18
|
extensions: []
|
|
18
19
|
extra_rdoc_files: []
|
|
19
20
|
files:
|
|
20
21
|
- CHANGELOG.md
|
|
22
|
+
- Gemfile.lock
|
|
21
23
|
- LICENSE-APACHE
|
|
22
24
|
- LICENSE-MIT
|
|
23
25
|
- README.md
|
|
24
26
|
- lib/veragem.rb
|
|
27
|
+
- lib/veragem/citation.rb
|
|
25
28
|
- lib/veragem/generator.rb
|
|
29
|
+
- lib/veragem/license.rb
|
|
26
30
|
- lib/veragem/name.rb
|
|
27
31
|
- lib/veragem/options.rb
|
|
28
32
|
- lib/veragem/project.rb
|
|
33
|
+
- lib/veragem/questions.rb
|
|
34
|
+
- lib/veragem/summary.rb
|
|
29
35
|
- lib/veragem/version.rb
|
|
30
36
|
- plugins.rb
|
|
31
37
|
- sig/bundler.rbs
|
|
32
38
|
- sig/veragem.rbs
|
|
33
39
|
- template/%name%.gemspec.erb
|
|
34
40
|
- template/.editorconfig
|
|
41
|
+
- template/.gitattributes
|
|
35
42
|
- template/.githooks/commit-msg
|
|
36
43
|
- template/.githooks/pre-commit
|
|
37
44
|
- template/.githooks/pre-push
|
|
@@ -46,16 +53,21 @@ files:
|
|
|
46
53
|
- template/.github/workflows/dependabot-automerge.yml
|
|
47
54
|
- template/.github/workflows/dependency-review.yml
|
|
48
55
|
- template/.github/workflows/image.yml
|
|
56
|
+
- template/.github/workflows/links.yml
|
|
49
57
|
- template/.github/workflows/nix.yml
|
|
50
58
|
- template/.github/workflows/release.yml
|
|
51
|
-
- template/.github/workflows/rubocop-autocorrect.yml
|
|
52
59
|
- template/.github/workflows/ruby-ci.yml
|
|
53
60
|
- template/.github/workflows/security.yml
|
|
54
61
|
- template/.github/workflows/style-check-cocogitto.yml
|
|
55
62
|
- template/.github/workflows/style-check-dprint.yml
|
|
56
63
|
- template/.gitignore
|
|
64
|
+
- template/.mutineer.yml
|
|
57
65
|
- template/.rubocop.yml
|
|
66
|
+
- template/.simplecov.erb
|
|
67
|
+
- template/.yard-lint.yml
|
|
68
|
+
- template/.yardopts
|
|
58
69
|
- template/AGENTS.md.erb
|
|
70
|
+
- template/CITATION.cff.erb
|
|
59
71
|
- template/CODE_OF_CONDUCT.md.erb
|
|
60
72
|
- template/CONTRIBUTING.md.erb
|
|
61
73
|
- template/Gemfile
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# A Dependabot pull request that moves Gemfile.lock gets RuboCop's safe corrections
|
|
2
|
-
# (`rake rubocop:autocorrect`), when the bumped RuboCop finds any, as a commit of their own on its
|
|
3
|
-
# branch, then merges as any bump once its checks pass. No token is stored: the job's GITHUB_TOKEN
|
|
4
|
-
# pushes, and GitHub may hold the checks of that token's commit until a maintainer approves them
|
|
5
|
-
# (the pull request's "Approve workflows to run"); no workflow can start them sooner -- dispatched,
|
|
6
|
-
# theirs are not the pull request's required checks. `[dependabot skip]`: Dependabot rebases the
|
|
7
|
-
# bump still, over the commit, and this workflow corrects the new one.
|
|
8
|
-
name: RuboCop Autocorrect
|
|
9
|
-
|
|
10
|
-
on:
|
|
11
|
-
pull_request:
|
|
12
|
-
paths:
|
|
13
|
-
- "Gemfile.lock"
|
|
14
|
-
|
|
15
|
-
permissions: {}
|
|
16
|
-
|
|
17
|
-
jobs:
|
|
18
|
-
correct:
|
|
19
|
-
name: Safe corrections
|
|
20
|
-
# Dependabot's own branches alone: never a fork's, never a person's pull request
|
|
21
|
-
if: >-
|
|
22
|
-
github.event.pull_request.user.login == 'dependabot[bot]' &&
|
|
23
|
-
github.event.pull_request.head.repo.full_name == github.repository
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
# the bumped gems run here, so this job's token writes nothing: the next job, which pushes,
|
|
26
|
-
# runs no gem
|
|
27
|
-
permissions:
|
|
28
|
-
contents: read
|
|
29
|
-
outputs:
|
|
30
|
-
changed: ${{ steps.correct.outputs.changed }}
|
|
31
|
-
steps:
|
|
32
|
-
- name: Checkout
|
|
33
|
-
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
34
|
-
with:
|
|
35
|
-
ref: ${{ github.event.pull_request.head.sha }}
|
|
36
|
-
persist-credentials: false
|
|
37
|
-
|
|
38
|
-
- name: Set up Ruby
|
|
39
|
-
uses: ruby/setup-ruby@7f797815d8adceb1c412e7abefdd1ab4abc47a5f # v1.335.0
|
|
40
|
-
with:
|
|
41
|
-
ruby-version: "4.0"
|
|
42
|
-
bundler-cache: true
|
|
43
|
-
|
|
44
|
-
- name: RuboCop's safe corrections
|
|
45
|
-
id: correct
|
|
46
|
-
run: |
|
|
47
|
-
set -euo pipefail
|
|
48
|
-
# what is left once corrected fails CI's own RuboCop, for a person to fix
|
|
49
|
-
bundle exec rake rubocop:autocorrect || true
|
|
50
|
-
git diff --binary > "$RUNNER_TEMP/corrections.patch"
|
|
51
|
-
if [[ -s $RUNNER_TEMP/corrections.patch ]]; then
|
|
52
|
-
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
53
|
-
fi
|
|
54
|
-
|
|
55
|
-
- name: Keep the corrections
|
|
56
|
-
if: steps.correct.outputs.changed == 'true'
|
|
57
|
-
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
58
|
-
with:
|
|
59
|
-
name: corrections
|
|
60
|
-
path: ${{ runner.temp }}/corrections.patch
|
|
61
|
-
if-no-files-found: error
|
|
62
|
-
|
|
63
|
-
push:
|
|
64
|
-
name: Commit them
|
|
65
|
-
needs: correct
|
|
66
|
-
if: needs.correct.outputs.changed == 'true'
|
|
67
|
-
runs-on: ubuntu-latest
|
|
68
|
-
permissions:
|
|
69
|
-
contents: write
|
|
70
|
-
steps:
|
|
71
|
-
- name: Checkout
|
|
72
|
-
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
73
|
-
with:
|
|
74
|
-
ref: ${{ github.event.pull_request.head.ref }}
|
|
75
|
-
# the push below uses it
|
|
76
|
-
persist-credentials: true
|
|
77
|
-
|
|
78
|
-
- name: The corrections
|
|
79
|
-
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
80
|
-
with:
|
|
81
|
-
name: corrections
|
|
82
|
-
path: ${{ runner.temp }}
|
|
83
|
-
|
|
84
|
-
- name: Commit and push
|
|
85
|
-
env:
|
|
86
|
-
BRANCH: ${{ github.event.pull_request.head.ref }}
|
|
87
|
-
CORRECTED: ${{ github.event.pull_request.head.sha }}
|
|
88
|
-
PATCH: ${{ runner.temp }}/corrections.patch
|
|
89
|
-
run: |
|
|
90
|
-
set -euo pipefail
|
|
91
|
-
# corrections of the commit they were made on: on a newer one, Dependabot's or these
|
|
92
|
-
# corrections', a re-run has nothing to do
|
|
93
|
-
if [[ $(git rev-parse HEAD) != "$CORRECTED" ]]; then
|
|
94
|
-
echo "$BRANCH is past $CORRECTED: corrected already, or a newer commit its own run corrects"
|
|
95
|
-
exit 0
|
|
96
|
-
fi
|
|
97
|
-
# RuboCop's files alone, edited in place: nothing else the bumped gems could write
|
|
98
|
-
ruby_files='^([^/]+/)*([^/]+\.(rb|gemspec)|Gemfile|Rakefile|Steepfile|(bin|exe)/[^/]+)$'
|
|
99
|
-
if [[ -n $(git apply --summary "$PATCH") ]] ||
|
|
100
|
-
git apply --numstat "$PATCH" | cut -f 3 | grep -Ev "$ruby_files"; then
|
|
101
|
-
echo "::error::the corrections change more than RuboCop's files, in place: not committed"
|
|
102
|
-
exit 1
|
|
103
|
-
fi
|
|
104
|
-
git apply "$PATCH"
|
|
105
|
-
git -c user.name="github-actions[bot]" \
|
|
106
|
-
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
|
|
107
|
-
commit --all --quiet --message "style: apply RuboCop's safe corrections [dependabot skip]"
|
|
108
|
-
if ! git push origin "HEAD:$BRANCH"; then
|
|
109
|
-
# refused because Dependabot pushed meanwhile, whose own run corrects its commit;
|
|
110
|
-
# refused otherwise, a failure
|
|
111
|
-
remote=$(git ls-remote origin "refs/heads/$BRANCH" | cut -f 1)
|
|
112
|
-
if [[ $remote == "$CORRECTED" ]]; then exit 1; fi
|
|
113
|
-
echo "$BRANCH moved on: its own run corrects it"
|
|
114
|
-
fi
|