Use issue_closing_pattern variable to close multiple issues in gitlab - ruby

I'd like to have the ability to close multiple issues with one commit by referencing multiple issues with the default pattern ^([Cc]loses|[Ff]ixes) +#\d+a. I know that this will only affect fixes #number-patterns at the beginning of lines and that's what I want.
But I wasn't yet able to get it to work.
I'm currently using Gitlab 6.1, installed it according to the installation readme on github and didn't change anything other then the codesnippet below.
Here's what I tried:
First I changed in {gitlab-directory}/app/models/commit.rb the following (original code commented out):
def closes_issues project
md = safe_message.scan(/(?i)((\[)\s*(close|fix)(s|es|d|ed)*\s*#\d+\s*(\])|(\()\s*(close|fix)(s|es|d|ed)*\s*#\d+\s*(\)))/)
#md = issue_closing_regex.match(safe_message)
if md
extractor = Gitlab::ReferenceExtractor.new
md.each do |n|
extractor.analyze(n[0])
end
extractor.issues_for(project)
#extractor = Gitlab::ReferenceExtractor.new
#extractor.analyze(md[0])
#extractor.issues_for(project)
else
[]
end
end
But the regex used in this code snippet doesn't fit my needs and isn't really correct (e.g.: (fixs #123) and (closees #123) would both work).
After testing this codesnippet and confirming that this one works with patterns that match the regex used in the snippet, I tried to change the regex. At first, I tried to do this in the second line:
md safe_message.scan(/#{Gitlab.config.gitlab.issue_closing_pattern}/)
This one didn't work. I didn't found any error messages in log/unicorn.stderr.log so I tried to use the default regex from the config file directly without variable:
md safe_message.scan(/^([Cc]loses|[Ff]ixes) +#\d+a/)
But this one didn't work, too. Again, no error messages in log/unicorn.stderr.log.
How do I use the variable issue_closing_pattern from the config file as regex pattern in this code snippet?

If the regex you provide to the String#scan method contains capture groups, it returns an array of arrays containing the patterns matched by each group:
irb(main):014:0> regex = "^([Cc]loses|[Ff]ixes) +#\\d+"
=> "^([Cc]loses|[Ff]ixes) +#\\d+"
irb(main):017:0> safe_message = "foo\ncloses #1\nfixes #2\nbar"
=> "foo\ncloses #1\nfixes #2\nbar"
irb(main):018:0> safe_message.scan(/#{regex}/)
=> [["closes"], ["fixes"]]
Because the default regex has a capture group for just the "closes/fixes" bit, that's all the loop is seeing, and those strings don't contain the issue references! To fix it, just add a capture group around the entire pattern:
irb(main):019:0> regex = "^(([Cc]loses|[Ff]ixes) +#\\d+)"
=> "^(([Cc]loses|[Ff]ixes) +#\\d+)"
irb(main):020:0> safe_message.scan(/#{regex}/)
=> [["closes #1", "closes"], ["fixes #2", "fixes"]]

Related

How do nested variables within the .env file work in CodeIgniter 4

Under the "Nesting Variables" section in Codeigniter4 site:
"To save on typing, you can reuse variables that you’ve already specified in the file by wrapping the variable name within ${...}"
link to CI nesting Variables section
example in the documentation:
BASE_DIR="/var/webroot/project-root"
CACHE_DIR="${BASE_DIR}/cache"
TMP_DIR="${BASE_DIR}/tmp"
I was trying to use the following
app.baseURL = 'http://localhost:8080/'
google.redirect = ${app.baseURL}Google
However, it's assigning it as a literal when print_r($_ENV)
[google.redirect] => ${app.baseURL}Google
I've tried using non-namespaced keys including BASE_DIR (per the example) and it keeps printing as a literal.
What's strange - When I use the following:
CI_ENVIRONMENT = development
google.redirect = ${CI_ENVIRONMENT}Google
The result when print_r is:
[CI_ENVIRONMENT] => development
[google.redirect] => developmentGoogle
My question is - What am I doing incorrectly and/or how should these be set/used correctly?
According to the documentation, I should be able to use any key within the .env file that was already assigned using
${somekeyinthisfile}
After a bit of looking, there is a more recent file up at
https://github.com/codeigniter4/CodeIgniter4/blob/develop/system/Config/DotEnv.php
with all the "other" changes...
This was a Bug Fix. So get that file and you will be good to go.
I am pretty sure that the intention wasn't to allow app.xxx settings to be used as variables as the documentation clearly shows, by not
showing them being used. ( yes its 6am now ...)
BUT it is your code to do with as you please...So if you want to use app.xxx as variables...
The Only Thing missing is the DOT (.) in the regex
If you look on Line 272 - system/Config/DotEnv.php inside method resolveNestedVariables() and add a . (dot) into the regex, that will make all your app.things work.
$value = preg_replace_callback(
'/\${([a-zA-Z0-9_.]+)}/',
function ($matchedPatterns) use ($loader) {
I have added a dot (.) at the end of the [a-zA-Z0-9_
So
'/\${([a-zA-Z0-9_]+)}/',
becomes
'/\${([a-zA-Z0-9_.]+)}/',

Is there a way to combine multiple regular expressions for a substring command?

Is there a way to combine these two regular expressions I am using to convert multi-platform file paths to a URL?
#image_file = "#{request.protocol}#{request.host}/#{#image_file.path.sub(/^([a-z]):\//,"")}".sub(/^\//,"")
This handles both my Windows and *IX platforms for file path conversion to a URL. For example, both of the following file path strings are handled properly:
- "c:\users\docs\pictures\image.jpg" goes to "http://localhost/users/docs/pictures/image.jpg"
- "\home\usr_name\pictures\image.jpg" goes to "http://localhost/usr_name/pictures/image.jpg"
I would prefer not to have to use two sub calls on a string if there is a way to combine them properly.
Suggestions and feedback from the community welcome!
The regex you are looking for is /^([a-z]:)?\//:
"c:/users/docs/pictures/image.jpg".sub(/^([a-z]:)?\//, '')
=> "users/docs/pictures/image.jpg"
"/home/usr_name/pictures/image.jpg".sub(/^([a-z]:)?\//, '')
=> "home/usr_name/pictures/image.jpg"
As some background on working with filenames and URLs...
First, Ruby doesn't require you to use reversed-slashes in Windows filenames, so if you're generating them don't bother. Instead, rely on the fact that the IO class knows what OS you're on and will auto-sense the path separator and convert things for you on the fly. This is from the IO documentation:
Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename "/gumby/ruby/test.rb" will be opened as "\gumby\ruby\test.rb". When specifying a Windows-style filename in a Ruby string, remember to escape the backslashes:
"c:\\gumby\\ruby\\test.rb"
Our examples here will use the Unix-style forward slashes; File::ALT_SEPARATOR can be used to get the platform-specific separator character.
If you're receiving the paths from another source, this makes it easy to normalize them into something Ruby likes:
path = "c:\\users\\docs\\pictures\\image.jpg" # => "c:\\users\\docs\\pictures\\image.jpg"
puts path
# >> c:\users\docs\pictures\image.jpg
path.gsub!(/\\/, '/') if path['\\']
path # => "c:/users/docs/pictures/image.jpg"
puts path
# >> c:/users/docs/pictures/image.jpg
For convenience, write a little helper method:
def normalize_path(p)
p.gsub(/\\/, '/')
end
normalize_path("c:\\users\\docs\\pictures\\image.jpg") # => "c:/users/docs/pictures/image.jpg"
normalize_path("/users/docs/pictures/image.jpg") # => "/users/docs/pictures/image.jpg"
Ruby's File and Pathname classes are very helpful when dealing with paths:
foo = normalize_path(path) # => "c:/users/docs/pictures/image.jpg"
File.dirname(foo) # => "c:/users/docs/pictures"
File.basename(foo) # => "image.jpg"
and:
File.split(foo) # => ["c:/users/docs/pictures", "image.jpg"]
path_to_file, filename = File.split(foo)
path_to_file # => "c:/users/docs/pictures"
filename # => "image.jpg"
Alternately there's the Pathname class:
require 'pathname'
bar = Pathname.new(foo)
bar.dirname # => #<Pathname:c:/users/docs/pictures>
bar.basename # => #<Pathname:image.jpg>
Pathname is an experimental class in Ruby's standard library that wraps up all the convenience methods from File, FileUtils and Dir into one umbrella class. It's worth getting to know:
The goal of this class is to manipulate file path information in a neater way than standard Ruby provides. The examples below demonstrate the difference.
All functionality from File, FileTest, and some from Dir and FileUtils is included, in an unsurprising way. It is essentially a facade for all of these, and more.
Back to your question...
Ruby's standard library also contains the URI class. It's well tested and is a better way to build URLs than simple string concatenation due to idiosyncrasies that can occur when characters need to be encoded.
require 'uri'
url = URI::HTTP.build({:host => 'www.foo.com', :path => foo[/^(?:[a-z]:)?(.+)/, 1]})
url # => #<URI::HTTP:0x007fe91117a438 URL:http://www.foo.com/users/docs/pictures/image.jpg>
The build method applies syntax rules to make sure the URL is valid.
If you need it, at this point you can tack on to_s to get the stringified version:
url.to_s # => "http://www.foo.com/users/docs/pictures/image.jpg"

nanoc: problems testing a compile rule by item name or identifier

I use the following tests in a nanoc rule for compiling various kinds of content (including partials) in multiple directories by matching them with their identically-named layouts.
Now I've added index files to each content dir, but these need the default layout. This obviously works fine if I add an item named 'index:' to the metadata in the 'index.md' files…
---
title: 'This page title'
index: 'y'
---
…but checking for if #item[:index] seems a bit clunky, so I've been trying (well, hacking around) to find a way to omit 'index:' from the metadata and test by nanoc rep name or identifier - see the commented-out if statements in the code below:
layouts = ['layoutone','layouttwo','layoutetc']
layouts.each do |dir|
compile "/#{dir}/*" do
# if item.identifier == "/#{dir}/index/"
# if item.identifier =~ %r{/\w/index/}
# if #item.rep_named(:index)
if #item[:index]
filter :kramdown
layout "default"
elsif #item[:inc]
filter :erb
filter :kramdown
layout "#{dir}"
else
filter :kramdown
layout "#{dir}"
end
end
end
What's wrong with the syntax/logic in my commented-out lines?
Edit:
I was missing the blindingly obvious here: simply add /content/dir_name.md at the same level as /content/dir_name/* to create /dir_name/index.html and /dir_name/*.html, and apply rules to those /content/dir_name.md files.
Did you change nanoc.yaml after nanoc create-site? Because I recall that by default, identifiers in nanoc don't contain the last index part of source file name.
Say, file content/dirA/index.markdown will have identifier /dirA/ or something, and compile to content/dirA/index.html. This may be the reason why your index regex didn't hit.
Yes, a little tricky, but nanoc is great.
update
I found a way to tell the content filename: item.raw_filename.
This document says it is only for binary files, while it also work on text files in my experiment.
# in compile block of Rules
item.identifier
# => "/aaa/"
item.raw_filename
# => "content/aaa.markdown"

Why is this generated ruby regex not working in the actual code?

I found a site where I can generate ruby regex.
So basically you enter the text and click the part you want to extract:
So I tried it:
product.css('.crAvgStars .swSprite span').text[/([+-]?\\d*\\.\\d+)(?![-+0-9\\.])/, 1]
To get the 4.4 but got nil instead.
Is the regex not working or I placed it in an incorrect way?
try this:
s = "4.4 out of 5 stars"
p s[/([+-]?\d*\.\d+)(?![-+0-9\.])/]
# >> "4.4"
You can find this wayRegexp.new:
Regexp.new('([+-]?\\d*\\.\\d+)(?![-+0-9\\.])')
# => /([+-]?\d*\.\d+)(?![-+0-9\.])/

Why won't gsub! change my files?

I am trying to do a simple find/replace on all text files in a directory, modifying any instance of [RAVEN_START: by inserting a string (in this case 'raven was here') before the line.
Here is the entire ruby program:
#!/usr/bin/env ruby
require 'rubygems'
require 'fileutils' #for FileUtils.mv('your file', 'new location')
class RavenParser
rawDir = Dir.glob("*.txt")
count = 0
rawDir.each do |ravFile|
#we have selected every text file, so now we have to search through the file
#and make the needed changes.
rav = File.open(ravFile, "r+") do |modRav|
#Now we've opened the file, and we need to do the operations.
if modRav
lines = File.open(modRav).readlines
lines.each { |line|
if line.match /\[RAVEN_START:.*\]/
line.gsub!(/\[RAVEN_START:/, 'raven was here '+line)
count = count + 1
end
}
printf("Total Changed: %d\n",count)
else
printf("No txt files found. \n")
end
end
#end of file replacing instructions.
end
# S
end
The program runs and compiles fine, but when I open up the text file, there has been no change to any of the text within the file. count increments properly (that is, it is equal to the number of instances of [RAVEN_START: across all the files), but the actual substitution is failing to take place (or at least not saving the changes).
Is my syntax on the gsub! incorrect? Am I doing something else wrong?
You're reading the data, updating it, and then neglecting to write it back to the file. You need something like:
# And save the modified lines.
File.open(modRav, 'w') { |f| f.puts lines.join("\n") }
immediately before or after this:
printf("Total Changed: %d\n",count)
As DMG notes below, just overwriting the file isn't properly paranoid as you could be interrupted in the middle of the write and lose data. If you want to be paranoid (which all of us should be because they really are out to get us), then you want to write to a temporary file and then do an atomic rename to replace the original file the new one. A rename generally only works when you stay within a single file system as there is no guarantee that the OS's temp directory (which Tempfile uses by default) will be on the same file system as modRav so File.rename might not even be an option with a Tempfile unless precautions are taken. But the Tempfile constructor takes a tmpdir parameter so we're saved:
modRavDir = File.dirname(File.realpath(modRav))
tmp = Tempfile.new(modRav, modRavDir)
tmp.write(lines.join("\n"))
tmp.close
File.rename(tmp.path, modRav)
You might want to stick that in a separate method (safe_save(modRav, lines) perhaps) to avoid further cluttering your block.
There is no gsub! in the post (except the title and question). I would actually recommend not using gsub!, but rather use the result of gsub -- avoiding mutability can help reduce a number of subtle bugs.
The line read from the file stream into a String is a copy and modifying it will not affect the contents of the file. (The general approach is to read a line, process the line, and write the line. Or do it all at once: read all lines, process all lines, write all processed lines. In either case, nothing is being written back to the file in the code in the post ;-)
Happy coding.
You're not using gsub!, you're using gsub. gsub! and gsub different methods, one does replacement on the object itself and the other does replacement then returns the result, respectively.
Change this
line.gsub(/\[RAVEN_START:/, 'raven was here '+line)
to this :
line.gsub!(/\[RAVEN_START:/, 'raven was here '+line)
or this:
line = line.gsub(/\[RAVEN_START:/, 'raven was here '+line)
See String#gsub for more info

Resources