blob: 75aac8921232553dba7f727b6b1569986d4ee094 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import pytest
from archery.release import (
Release, MajorRelease, MinorRelease, PatchRelease,
Jira, Version, Issue, CommitTitle, Commit
)
from archery.testing import DotDict
# subset of issues per revision
_issues = {
"1.0.1": [
Issue("ARROW-9684", type="Bug", summary="[C++] Title"),
Issue("ARROW-9667", type="New Feature", summary="[Crossbow] Title"),
Issue("ARROW-9659", type="Bug", summary="[C++] Title"),
Issue("ARROW-9644", type="Bug", summary="[C++][Dataset] Title"),
Issue("ARROW-9643", type="Bug", summary="[C++] Title"),
Issue("ARROW-9609", type="Bug", summary="[C++] Title"),
Issue("ARROW-9606", type="Bug", summary="[C++][Dataset] Title")
],
"1.0.0": [
Issue("ARROW-300", type="New Feature", summary="[Format] Title"),
Issue("ARROW-4427", type="Task", summary="[Doc] Title"),
Issue("ARROW-5035", type="Improvement", summary="[C#] Title"),
Issue("ARROW-8473", type="Bug", summary="[Rust] Title"),
Issue("ARROW-8472", type="Bug", summary="[Go][Integration] Title"),
Issue("ARROW-8471", type="Bug", summary="[C++][Integration] Title"),
Issue("ARROW-8974", type="Improvement", summary="[C++] Title"),
Issue("ARROW-8973", type="New Feature", summary="[Java] Title")
],
"0.17.1": [
Issue("ARROW-8684", type="Bug", summary="[Python] Title"),
Issue("ARROW-8657", type="Bug", summary="[C++][Parquet] Title"),
Issue("ARROW-8641", type="Bug", summary="[Python] Title"),
Issue("ARROW-8609", type="Bug", summary="[C++] Title"),
],
"0.17.0": [
Issue("ARROW-2882", type="New Feature", summary="[C++][Python] Title"),
Issue("ARROW-2587", type="Bug", summary="[Python] Title"),
Issue("ARROW-2447", type="Improvement", summary="[C++] Title"),
Issue("ARROW-2255", type="Bug", summary="[Integration] Title"),
Issue("ARROW-1907", type="Bug", summary="[C++/Python] Title"),
Issue("ARROW-1636", type="New Feature", summary="[Format] Title")
]
}
class FakeJira(Jira):
def __init__(self):
pass
def project_versions(self, project='ARROW'):
return [
Version.parse("3.0.0", released=False),
Version.parse("2.0.0", released=False),
Version.parse("1.1.0", released=False),
Version.parse("1.0.1", released=False),
Version.parse("1.0.0", released=True),
Version.parse("0.17.1", released=True),
Version.parse("0.17.0", released=True),
Version.parse("0.16.0", released=True),
Version.parse("0.15.2", released=True),
Version.parse("0.15.1", released=True),
Version.parse("0.15.0", released=True),
]
def project_issues(self, version, project='ARROW'):
return _issues[str(version)]
@pytest.fixture
def fake_jira():
return FakeJira()
def test_version(fake_jira):
v = Version.parse("1.2.5")
assert str(v) == "1.2.5"
assert v.major == 1
assert v.minor == 2
assert v.patch == 5
assert v.released is False
assert v.release_date is None
v = Version.parse("1.0.0", released=True, release_date="2020-01-01")
assert str(v) == "1.0.0"
assert v.major == 1
assert v.minor == 0
assert v.patch == 0
assert v.released is True
assert v.release_date == "2020-01-01"
def test_issue(fake_jira):
i = Issue("ARROW-1234", type='Bug', summary="title")
assert i.key == "ARROW-1234"
assert i.type == "Bug"
assert i.summary == "title"
assert i.project == "ARROW"
assert i.number == 1234
i = Issue("PARQUET-1111", type='Improvement', summary="another title")
assert i.key == "PARQUET-1111"
assert i.type == "Improvement"
assert i.summary == "another title"
assert i.project == "PARQUET"
assert i.number == 1111
fake_jira_issue = DotDict({
'key': 'ARROW-2222',
'fields': {
'issuetype': {
'name': 'Feature'
},
'summary': 'Issue title'
}
})
i = Issue.from_jira(fake_jira_issue)
assert i.key == "ARROW-2222"
assert i.type == "Feature"
assert i.summary == "Issue title"
assert i.project == "ARROW"
assert i.number == 2222
def test_commit_title():
t = CommitTitle.parse(
"ARROW-9598: [C++][Parquet] Fix writing nullable structs"
)
assert t.project == "ARROW"
assert t.issue == "ARROW-9598"
assert t.components == ["C++", "Parquet"]
assert t.summary == "Fix writing nullable structs"
t = CommitTitle.parse(
"ARROW-8002: [C++][Dataset][R] Support partitioned dataset writing"
)
assert t.project == "ARROW"
assert t.issue == "ARROW-8002"
assert t.components == ["C++", "Dataset", "R"]
assert t.summary == "Support partitioned dataset writing"
t = CommitTitle.parse(
"ARROW-9600: [Rust][Arrow] pin older version of proc-macro2 during "
"build"
)
assert t.project == "ARROW"
assert t.issue == "ARROW-9600"
assert t.components == ["Rust", "Arrow"]
assert t.summary == "pin older version of proc-macro2 during build"
t = CommitTitle.parse("[Release] Update versions for 1.0.0")
assert t.project is None
assert t.issue is None
assert t.components == ["Release"]
assert t.summary == "Update versions for 1.0.0"
t = CommitTitle.parse("[Python][Doc] Fix rst role dataset.rst (#7725)")
assert t.project is None
assert t.issue is None
assert t.components == ["Python", "Doc"]
assert t.summary == "Fix rst role dataset.rst (#7725)"
t = CommitTitle.parse(
"PARQUET-1882: [C++] Buffered Reads should allow for 0 length"
)
assert t.project == 'PARQUET'
assert t.issue == 'PARQUET-1882'
assert t.components == ["C++"]
assert t.summary == "Buffered Reads should allow for 0 length"
t = CommitTitle.parse(
"ARROW-9340 [R] Use CRAN version of decor package "
"\nsomething else\n"
"\nwhich should be truncated"
)
assert t.project == 'ARROW'
assert t.issue == 'ARROW-9340'
assert t.components == ["R"]
assert t.summary == "Use CRAN version of decor package "
def test_release_basics(fake_jira):
r = Release.from_jira("1.0.0", jira=fake_jira)
assert isinstance(r, MajorRelease)
assert r.is_released is True
assert r.branch == 'master'
assert r.tag == 'apache-arrow-1.0.0'
r = Release.from_jira("1.1.0", jira=fake_jira)
assert isinstance(r, MinorRelease)
assert r.is_released is False
assert r.branch == 'maint-1.x.x'
assert r.tag == 'apache-arrow-1.1.0'
# minor releases before 1.0 are treated as major releases
r = Release.from_jira("0.17.0", jira=fake_jira)
assert isinstance(r, MajorRelease)
assert r.is_released is True
assert r.branch == 'master'
assert r.tag == 'apache-arrow-0.17.0'
r = Release.from_jira("0.17.1", jira=fake_jira)
assert isinstance(r, PatchRelease)
assert r.is_released is True
assert r.branch == 'maint-0.17.x'
assert r.tag == 'apache-arrow-0.17.1'
def test_previous_and_next_release(fake_jira):
r = Release.from_jira("3.0.0", jira=fake_jira)
assert isinstance(r.previous, MajorRelease)
assert r.previous.version == Version.parse("2.0.0")
with pytest.raises(ValueError, match="There is no upcoming release set"):
assert r.next
r = Release.from_jira("2.0.0", jira=fake_jira)
assert isinstance(r.previous, MajorRelease)
assert isinstance(r.next, MajorRelease)
assert r.previous.version == Version.parse("1.0.0")
assert r.next.version == Version.parse("3.0.0")
r = Release.from_jira("1.1.0", jira=fake_jira)
assert isinstance(r.previous, MajorRelease)
assert isinstance(r.next, MajorRelease)
assert r.previous.version == Version.parse("1.0.0")
assert r.next.version == Version.parse("2.0.0")
r = Release.from_jira("1.0.0", jira=fake_jira)
assert isinstance(r.next, MajorRelease)
assert isinstance(r.previous, MajorRelease)
assert r.previous.version == Version.parse("0.17.0")
assert r.next.version == Version.parse("2.0.0")
r = Release.from_jira("0.17.0", jira=fake_jira)
assert isinstance(r.previous, MajorRelease)
assert r.previous.version == Version.parse("0.16.0")
r = Release.from_jira("0.15.2", jira=fake_jira)
assert isinstance(r.previous, PatchRelease)
assert isinstance(r.next, MajorRelease)
assert r.previous.version == Version.parse("0.15.1")
assert r.next.version == Version.parse("0.16.0")
r = Release.from_jira("0.15.1", jira=fake_jira)
assert isinstance(r.previous, MajorRelease)
assert isinstance(r.next, PatchRelease)
assert r.previous.version == Version.parse("0.15.0")
assert r.next.version == Version.parse("0.15.2")
def test_release_issues(fake_jira):
# major release issues
r = Release.from_jira("1.0.0", jira=fake_jira)
assert r.issues.keys() == set([
"ARROW-300",
"ARROW-4427",
"ARROW-5035",
"ARROW-8473",
"ARROW-8472",
"ARROW-8471",
"ARROW-8974",
"ARROW-8973"
])
# minor release issues
r = Release.from_jira("0.17.0", jira=fake_jira)
assert r.issues.keys() == set([
"ARROW-2882",
"ARROW-2587",
"ARROW-2447",
"ARROW-2255",
"ARROW-1907",
"ARROW-1636",
])
# patch release issues
r = Release.from_jira("1.0.1", jira=fake_jira)
assert r.issues.keys() == set([
"ARROW-9684",
"ARROW-9667",
"ARROW-9659",
"ARROW-9644",
"ARROW-9643",
"ARROW-9609",
"ARROW-9606"
])
@pytest.mark.parametrize(('version', 'ncommits'), [
("1.0.0", 771),
("0.17.1", 27),
("0.17.0", 569),
("0.15.1", 41)
])
def test_release_commits(fake_jira, version, ncommits):
r = Release.from_jira(version, jira=fake_jira)
assert len(r.commits) == ncommits
for c in r.commits:
assert isinstance(c, Commit)
assert isinstance(c.title, CommitTitle)
assert c.url.endswith(c.hexsha)
def test_maintenance_patch_selection(fake_jira):
r = Release.from_jira("0.17.1", jira=fake_jira)
shas_to_pick = [
c.hexsha for c in r.commits_to_pick(exclude_already_applied=False)
]
expected = [
'8939b4bd446ee406d5225c79d563a27d30fd7d6d',
'bcef6c95a324417e85e0140f9745d342cd8784b3',
'6002ec388840de5622e39af85abdc57a2cccc9b2',
'9123dadfd123bca7af4eaa9455f5b0d1ca8b929d',
]
assert shas_to_pick == expected