-
Notifications
You must be signed in to change notification settings - Fork 309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DAOS-12950 test: auto-determine test tags #13315
Changes from 3 commits
c6f6acb
da74716
e8c4f3b
14a77be
661dbd4
2b3af31
188afe6
102c4f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,3 +40,14 @@ jobs: | |
ref: ${{ github.event.pull_request.head.sha }} | ||
- name: Check DAOS logging macro use. | ||
run: ./utils/cq/d_logging_check.py --github src | ||
|
||
ftest-tags: | ||
name: Ftest tag check | ||
runs-on: ubuntu-22.04 | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
with: | ||
ref: ${{ github.event.pull_request.head.sha }} | ||
- name: Check DAOS ftest tags. | ||
run: ./src/tests/ftest/tags.py lint | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be protected against PRs where this check has landed but PRs aren't including it yet. I can send you code for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't follow. Do GHA for PRs use the master workflows? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a check |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -326,7 +326,7 @@ pipeline { | |
stage('Get Commit Message') { | ||
steps { | ||
script { | ||
env.COMMIT_MESSAGE = sh(script: 'git show -s --format=%B', | ||
env.COMMIT_MESSAGE = sh(script: 'ci/get_commit_message.py --target origin/' + target_branch, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason for doing it this way is to prevent needing to modify pipelinelib. |
||
returnStdout: true).trim() | ||
Map pragmas = [:] | ||
// can't use eachLine() here: https://issues.jenkins.io/browse/JENKINS-46988/ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the idea of an API to query the test tags from something, be that a commit message, a string or a target sha etc. I think that's what this file is but if that's the case then it needs to be better documented and probably a clearer interface. I'm also sceptical if re is required or just split(:) would suffice. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
To rely on just There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a function to do it in https://github.com/daos-stack/daos/pull/8483/files but it's really very simple. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For reference, this is with
And this is manually:
Personally, I think |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
#!/usr/bin/env python3 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: add copyright |
||
"""Get the latest commit message with some modifications.""" | ||
|
||
import importlib.util | ||
import os | ||
import re | ||
import subprocess # nosec | ||
from argparse import ArgumentParser | ||
|
||
PARENT_DIR = os.path.dirname(__file__) | ||
|
||
|
||
# Dynamically load the tags | ||
tags_path = os.path.realpath( | ||
os.path.join(PARENT_DIR, '..', 'src', 'tests', 'ftest', 'tags.py')) | ||
tags_spec = importlib.util.spec_from_file_location('tags', tags_path) | ||
tags = importlib.util.module_from_spec(tags_spec) | ||
tags_spec.loader.exec_module(tags) | ||
Comment on lines
+13
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative is to use |
||
|
||
|
||
def git_commit_message(): | ||
"""Get the latest git commit message. | ||
|
||
Returns: | ||
str: the commit message | ||
""" | ||
result = subprocess.run( | ||
['git', 'show', '-s', '--format=%B'], | ||
stdout=subprocess.PIPE, check=True, cwd=PARENT_DIR) | ||
return result.stdout.decode().rstrip('\n') | ||
|
||
|
||
def git_root_dir(): | ||
"""Get the git root directory. | ||
|
||
Returns: | ||
str: the root directory path | ||
""" | ||
result = subprocess.run( | ||
['git', 'rev-parse', '--show-toplevel'], | ||
stdout=subprocess.PIPE, check=True, cwd=PARENT_DIR) | ||
return result.stdout.decode().rstrip('\n') | ||
|
||
|
||
def git_files_changed(target): | ||
"""Get a list of files from git diff. | ||
|
||
Args: | ||
target (str): target branch or commit. | ||
|
||
Returns: | ||
list: absolute paths of modified files | ||
""" | ||
git_root = git_root_dir() | ||
result = subprocess.run( | ||
['git', 'diff', target, '--name-only', '--relative'], | ||
stdout=subprocess.PIPE, cwd=git_root, check=True) | ||
return [os.path.join(git_root, path) for path in result.stdout.decode().split('\n') if path] | ||
Comment on lines
+54
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This root dir logic is so you could technically call this from anywhere in the repo
Comment on lines
+54
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't correct in the case where the branch isn't up-to-date with the target. It needs logic similar to |
||
|
||
|
||
def modify_commit_message_pragmas(commit_message, target): | ||
"""Modify the commit message pragmas. | ||
|
||
TODO: if a commit already has Test-tag, do not overwrite. Just comment the suggested. | ||
|
||
Args: | ||
commit_message (str): the original commit message | ||
target (str): where the current branch is intended to be merged | ||
|
||
Returns: | ||
str: the modified commit message | ||
""" | ||
modified_files = git_files_changed(target) | ||
|
||
rec_tags = tags.files_to_tags(modified_files) | ||
|
||
# Extract all "Features" and "Test-tag" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pipeline lib doesn't support both Features and Test-tag so this combines them into one |
||
feature_tags = re.findall( | ||
r'^Features:(.*)$', commit_message, flags=re.MULTILINE | re.IGNORECASE) | ||
if feature_tags: | ||
for _tags in feature_tags: | ||
rec_tags.update(filter(None, _tags.split(' '))) | ||
commit_message = re.sub( | ||
r'^Features:.*$', '', commit_message, flags=re.MULTILINE | re.IGNORECASE) | ||
test_tags = re.findall( | ||
r'^Test-tag:(.*)$', commit_message, flags=re.MULTILINE | re.IGNORECASE) | ||
if test_tags: | ||
for _tags in test_tags: | ||
rec_tags.update(filter(None, _tags.split(' '))) | ||
commit_message = re.sub( | ||
r'^Test-tag:.*$', '', commit_message, flags=re.MULTILINE | re.IGNORECASE) | ||
|
||
# Put "Test-tag" after the title | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think common use (even outside of our team) is that pragmas (i.e. GH's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that a requirement? It's much easier to insert after the title because we don't have to look for a SoB. And personally, I prefer pragmas up front in my own commit messages so they are clearly visible. Though, this modified commit message would only be in Jenkins, not the actual commit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've always put them at the end. Put the human-readable bit at the beginning where it can be seen and the machine readable bit at the end out of the way. Like Dalton says however this doesn't appear to matter but it does highlight that the way this code is communicating with ftest is something we might be able to improve. |
||
commit_message_split = commit_message.splitlines() | ||
commit_message_split.insert(1, '') | ||
commit_message_split.insert(2, '# Auto-recommended Test-tag') | ||
commit_message_split.insert(3, f'Test-tag: {" ".join(sorted(rec_tags))}') | ||
return os.linesep.join(commit_message_split) | ||
|
||
|
||
def main(): | ||
parser = ArgumentParser() | ||
parser.add_argument( | ||
"--target", | ||
help="if given, used to modify commit pragmas") | ||
args = parser.parse_args() | ||
|
||
if args.target: | ||
print(modify_commit_message_pragmas(git_commit_message(), args.target)) | ||
else: | ||
print(git_commit_message()) | ||
Comment on lines
+115
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The option to run with --target is just in case we need a failsafe if something goes wrong in the tag logic |
||
|
||
|
||
if __name__ == '__main__': | ||
main() |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know why this file is needed in the RPM but I'd back out this change for now to avoid conflicts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally, it would useful to have this utility available to probe for things like "what tags do I need to run this test" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,10 @@ | ||
daos (2.5.100-10) unstable; urgency=medium | ||
daos (2.5.100-11) unstable; urgency=medium | ||
[ Dalton Bohning ] | ||
* Add tags.py | ||
|
||
-- Dalton Bohning <[email protected]> Wed, 08 Nov 2023 12:00:00 -0500 | ||
|
||
daos (2.5.100-10) unstable; urgency=medium | ||
[ Phillip Henderson ] | ||
* Move verify_perms.py location | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
# Dummy change | ||
hosts: | ||
test_servers: 1 | ||
test_clients: 1 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normal behaviour is to checkout a merge commit with the target branch, this code will checkout the branch itself.
The difference comes in annotating against line numbers, with a merge commit they might be wrong although of course with a branch checkout you're not testing what would be landed. Unless you're annotating the PR against specific lines in files you probably don't want this, if you're just failing the build with logging or annotating against files (which I think is done against "line 0" then you don't want to specify a ref here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. The ftest lint just fails with logging + exit(1). No specific lines or files are annotated. So I think I want the default behavior