如何在Jenkins / Groovy中使用多行正则表达式匹配

huangapple go评论150阅读模式
英文:

How do I use multiline regex match in Jenkins / Groovy

问题

In Jenkins,我正在构建一个步骤,该步骤读取CHANGELOG.md并使用正则表达式从给定版本中提取最新的更改日志。

用到的.groovy代码:

  1. def currentTag = '0.1.0'
  2. def changelogFileName = 'CHANGELOG.md'
  3. def changelogText = readFile(file: changelogFileName)
  4. def pattern = "(?s)^## ${currentTag}.*?(?=\\n\\n## |\\z)"
  5. def matcher = (changelogText =~ pattern)
  6. if (matcher.find()) {
  7. def latestChangelog = matcher.group()
  8. println(latestChangelog.strip())
  9. } else {
  10. println('无法解析最新的更改日志。')
  11. }

用到的输入文件:

  1. # Changelog - 项目
  2. 所有显著的更改将在此文件中记录。
  3. 本项目遵循[语义化版本](http://semver.org/)。
  4. 根据[Keep a CHANGELOG](http://keepachangelog.com/)的准则编写的更改日志。
  5. ## 0.3.0 - 2022-06-30
  6. ### 更改:
  7. - MDN-XXXX: blabla
  8. ### 还有更改:
  9. - MDN-XXXX: blabla
  10. ## 0.2.0 - 2022-06-09
  11. ### 添加:
  12. - MDN-XXXX: blabla
  13. ## 0.1.1 - 2022-06-08
  14. ### 修复:
  15. - MDN-XXXX: blabla
  16. ## 0.1.0 - 2022-06-08
  17. ### 添加:
  18. - MDN-XXXX: blabla
  19. - MDN-XXXX: blabla

在本地,此代码运行得很好。
但是,我想在Jenkins中使用它,那里直接导入这些内容会存在安全问题:

  1. import java.nio.file.Files
  2. import java.nio.file.Paths
  3. import java.util.regex.Pattern

因此,我需要将其更改为适用于Jenkins的代码。

所以我将它更改为以下内容:

  1. def changelogText = readFile(file: changelogFileName)
  2. def pattern = "(?s)^## ${currentTag}.*?(?=\\n\\n## |\\z)"
  3. def matcher = (changelogText =~ pattern)
  4. if (matcher.find()) {
  5. def latestChangelog = matcher.group()
  6. println(latestChangelog.strip())
  7. } else {
  8. println('无法解析最新的更改日志。')
  9. }

但是,我一直收到'无法解析最新的更改日志。'的消息。

当我不得不一直在Jenkins上运行它时,调试起来非常困难。
是否有人知道如何在本地使Jenkins库可用,或者更好的是,如何使用Pattern.MULTILINE进行匹配?

或者对于完全不同的方法是否有建议?

英文:

In Jenkins I'm building a step that reads CHANGELOG.md and uses regex to extract the latest changelog from giving version.

The used .groovy code:

  1. #!/usr/bin/env groovy
  2. import java.nio.file.Files
  3. import java.nio.file.Paths
  4. import java.util.regex.Pattern
  5. def String currentTag = '0.1.0';
  6. def String changelogFileName = 'CHANGELOG.md';
  7. def changelogText = new String(Files.readAllBytes(Paths.get(changelogFileName)))
  8. def pattern = Pattern.compile("(?s)^## ${currentTag}.*?(?=\n\n## |\\z)", Pattern.MULTILINE)
  9. def matcher = pattern.matcher(changelogText)
  10. if (matcher.find()) {
  11. def latestChangelog = matcher.group()
  12. println latestChangelog.strip()
  13. }

The used input file:

  1. # Changelog - Project
  2. All notable changes to this project will be documented in this file.
  3. This project adheres to [Semantic Versioning](http://semver.org/).
  4. Changelog based on guidelines from
  5. [Keep a CHANGELOG](http://keepachangelog.com/).
  6. ## 0.3.0 - 2022-06-30
  7. ### Changed:
  8. - MDN-XXXX: blabla
  9. ### Also Changed:
  10. - MDN-XXXX: blabla
  11. ## 0.2.0 - 2022-06-09
  12. ### Added:
  13. - MDN-XXXX: blabla
  14. ## 0.1.1 - 2022-06-08
  15. ### Fixed:
  16. - MDN-XXXX: blabla
  17. ## 0.1.0 - 2022-06-08
  18. ### Added:
  19. - MDN-XXXX: blabla
  20. - MDN-XXXX: blabla

Locally this code works great.
However, I want to use it in Jenkins, and there it's a security issues to directly import these:

  1. import java.nio.file.Files
  2. import java.nio.file.Paths
  3. import java.util.regex.Pattern

Hence, I need to change it to Jenkins friendly code.

So I changed it to this:

  1. def changelogText = readFile(file: changelogFileName)
  2. def pattern = "(?s)^## ${currentTag}.*?(?=\n\n## |\\z)"
  3. def matcher = (changelogText =~ pattern)
  4. if (matcher.find()) {
  5. def latestChangelog = matcher.group();
  6. println(latestChangelog.strip());
  7. } else {
  8. println('Could not parse latest changelog.');
  9. }

However, I keep getting 'Could not parse latest changelog.'

It's quite hard to debug when I have to run it on Jenkins the whole time.
Does anyone know how to make the Jenkins libraries available locally, or better, how I can match using Pattern.MULTILINE?

Or perhaps a suggestion for a whole different approach?

答案1

得分: 1

以下是您要翻译的内容:

如果有人想要使用 awk,这是一个 awk 解决方案,但我仍然更喜欢上面的解决方案,因为如果最后一个条目 0.1.0 中有空行的话,它更好。

  1. #!/usr/bin/env groovy
  2. /**
  3. * 从给定的文件名和标签获取最新的更改日志数据
  4. * @param currentTag 字符串
  5. * @param changelogFileName 字符串
  6. */
  7. def call(
  8. String currentTag = '0.1.0',
  9. String changelogFileName = 'CHANGELOG.md'
  10. ) {
  11. def changelogText = sh(returnStdout: true, script: "awk '{ RS=\"\" } /## ${currentTag}.*?(^## |$)/' ${changelogFileName}").strip();
  12. if (changelogText) {
  13. return changelogText;
  14. } else {
  15. return "无法解析 ${changelogFileName} 中标签 ${currentTag} 的更改日志。更改日志已推送吗?或者更改日志可能包含语法错误?";
  16. }
  17. }

希望这有所帮助!如果您需要进一步的翻译,请告诉我。

英文:

In case someone wants to use awk instead, this in an awk solution, however, I still prefer the above one as it's better in case if the last entry 0.1.0 has some empty lines in it.

  1. #!/usr/bin/env groovy
  2. /**
  3. * Get latest changelog data from given filename and tag
  4. * @param currentTag string
  5. * @param changelogFileName string
  6. */
  7. def call(
  8. String currentTag = '0.1.0',
  9. String changelogFileName = 'CHANGELOG.md'
  10. ) {
  11. def changelogText = sh(returnStdout: true, script: "awk '{ RS=\"\" } /## ${currentTag}.*?(^## |$)/' ${changelogFileName}").strip();
  12. if (changelogText) {
  13. return changelogText;
  14. } else {
  15. return "Could not parse the changelog of tag ${currentTag} in ${changelogFileName}. Is changelog pushed? Or perhaps the changelog contains a syntax error?";
  16. }
  17. }

答案2

得分: 1

要匹配包括换行符在内的所有符号,您可以使用 [\s\S]。这将在没有任何标志的情况下工作。

考虑以下示例:

  1. String changelogText = """
  2. # Changelog - Project
  3. All notable changes to this project will be documented in this file.
  4. This project adheres to [Semantic Versioning](http://semver.org/).
  5. Changelog based on guidelines from
  6. [Keep a CHANGELOG](http://keepachangelog.com/).
  7. ## 0.3.0 - 2022-06-30
  8. ### Changed:
  9. - MDN-XXXX: blabla
  10. ### Also Changed:
  11. - MDN-XXXX: blabla
  12. ## 0.2.0 - 2022-06-09
  13. ### Added:
  14. - MDN-XXXX: blabla
  15. ## 0.1.1 - 2022-06-08
  16. ### Fixed:
  17. - MDN-XXXX: blabla
  18. ## 0.1.0 - 2022-06-08
  19. ### Added:
  20. - MDN-XXXX: blabla
  21. - MDN-XXXX: blabla
  22. """
  23. def currentTag = "0.2.0 - 2022-06-09"
  24. def pattern = /## ${currentTag}[\s\S]*?(?=\n\n## |\z)/
  25. def matcher = (changelogText =~ pattern)
  26. if (matcher.find()) {
  27. def latestChangelog = matcher[0];
  28. println(latestChangelog);
  29. } else {
  30. println('Could not parse latest changelog.');
  31. }

输出:

  1. ## 0.2.0 - 2022-06-09
  2. ### Added:
  3. - MDN-XXXX: blabla
英文:

To match all symbols including newlines, you can use [\s\S]. This will work without any flags.

Consider the following demo:

  1. String changelogText = """
  2. # Changelog - Project
  3. All notable changes to this project will be documented in this file.
  4. This project adheres to [Semantic Versioning](http://semver.org/).
  5. Changelog based on guidelines from
  6. [Keep a CHANGELOG](http://keepachangelog.com/).
  7. ## 0.3.0 - 2022-06-30
  8. ### Changed:
  9. - MDN-XXXX: blabla
  10. ### Also Changed:
  11. - MDN-XXXX: blabla
  12. ## 0.2.0 - 2022-06-09
  13. ### Added:
  14. - MDN-XXXX: blabla
  15. ## 0.1.1 - 2022-06-08
  16. ### Fixed:
  17. - MDN-XXXX: blabla
  18. ## 0.1.0 - 2022-06-08
  19. ### Added:
  20. - MDN-XXXX: blabla
  21. - MDN-XXXX: blabla
  22. """
  23. def currentTag = "0.2.0 - 2022-06-09"
  24. def pattern = /## ${currentTag}[\s\S]*?(?=\n\n## |\z)/
  25. def matcher = (changelogText =~ pattern)
  26. if (matcher.find()) {
  27. def latestChangelog = matcher[0];
  28. println(latestChangelog);
  29. } else {
  30. println('Could not parse latest changelog.');
  31. }

Output:

  1. ## 0.2.0 - 2022-06-09
  2. ### Added:
  3. - MDN-XXXX: blabla

huangapple
  • 本文由 发表于 2023年7月5日 00:51:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76614593.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定