-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
stable
version stuck on a specific commit
#3913
Conversation
I going to try to find the root of the problem and fix it here. |
I saw that there is a test case that allows the user to re-define the stable version But the problem with that is that if the user wants to delete that version later, it can't. |
32e8c0e
to
2ab9257
Compare
e6e6e5e
to
de0d86f
Compare
stable
version stuch on a specific commitstable
version stuck on a specific commit
) | ||
self.assertEqual(resp.status_code, 200) | ||
|
||
self.pip.refresh_from_db() |
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.
I'm not sure if this is necessary 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.
As a general rule:
refresh_from_db
is needed when you have a db object already in memory and the registry in the db is changed by an external reason (celery, api request, HTTP post request, etc). So, in that case, the object in memory has to be refreshed from the db to have the new values.
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.
Related fields (those one that generate new queries to db) are not affected by this. For example, self.pip.versions.all()
will hit the db and it's not affected by an old self.pip
in memory.
self.assertFalse(version_9.active) | ||
|
||
# Did update to user-defined stable version | ||
version_stable = Version.objects.get(slug='stable') | ||
version_stable = self.pip.versions.get(slug='stable') |
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.
The version can collide with another fixture project
Same bug when a user creates a |
# is created. | ||
self.pip.save() | ||
|
||
def test_user_defined_latest_version_tag(self): |
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.
This test is failing. When the user creates a tag named latest
, a new version is created latest_a
. Is that the desired behavior?
/cc @humitos
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.
I'm thinking about this.
-
If the user creates a
latest
and we just change ourmachine
toFalse
: that project looses the ability to build the latest changes in their repo. I mean, new commits toProject.default_branch
won't trigger any build. Is that what we want?- this behaviour seems to be compatible with what the
stable
branch will do in a similar case
- this behaviour seems to be compatible with what the
-
having
latest
andlatest_a
seems to be confusing to me. Also, supposing that you want to point your readers to your latest: the url will be/latest_a
which probably people won't like anyway -
I'm not sure if we have some chunk of code dependent/assuming that we will always have a
LATEST
Version withmachine=True
--that's a good checking to do before make a decision.- can you check this?
For now, it seems that what we want is the first idea of just changing the
machine
field toFalse
. I'd like more input here, though.
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.
I didn't find any query that depends on machine=True
for latest, but I did find some interesting relation between latest
and default_branch
on the code
I think the use case of having a custom latest
is covered by the default branch setting
BUT, what happens when the user wants a commit/tag as the latest version (very weird though)?
I did a quick test with a commit and a tag, nothing breaks (even if they are marked as a branch).
So, the final question, how to handle this when a user creates a tag named latest
? If the users want the URL to be /latest/
, then putting the tag name on the default_branch
setting can achieve this.
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.
OK, so it seems that what we want is:
- if the user defines a
latest
branch, remove themachine=True
and handle it as a common branch - if the user wants to trigger new builds on a non-default-latest branch, he can change the
default_branch
in the admin - do not create a
latest_a
if the users defines alatest
branch/tag on the repo
Does these thoughts answer your questions and unblock you to continue with this PR?
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.
What would happen if a user creates a latest
tag and also touch the setting for default_branch
? (very extreme case, I don't know if even worth considering p:)
According to
Her/his initial latest would change.
Anyway, I'm going to write more tests to check the requirements, but I think these changes are going to break others parts of the code that depends on latest, hope not.
@@ -152,6 +152,484 @@ def test_new_tag_update_inactive(self): | |||
version_8 = Version.objects.get(slug='0.8.3') | |||
self.assertFalse(version_8.active) | |||
|
|||
def test_normal_behavior_for_stable_after_deleting_user_defined_tag(self): |
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.
Can you use pytest.mark.xfail(strict=True)
here? That way, these test will fail and pytest won't fail but pytest will fail when you write the logic and they start passing.
on the user repository, the RTD's ``stable`` is back. | ||
""" | ||
# There isn't a stable version yet | ||
self.pip.versions.exclude(slug='master').delete() |
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.
OK, this doesn't feel quite right. But all tests are using the pip project... Should I start using a dynamic fixture instead or should I use something else? /cc @humitos
Also, there aren't tests for new projects with already created tags/branches with latest and stable. I'm going to add them (maybe is kind of more convenient to use the dynamic fixtures because more tests are going to use it).
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.
You can remove that version inside your test and it won't affect the others since the fixture is loaded one each test: https://docs.djangoproject.com/en/2.0/topics/testing/tools/#topics-testing-fixtures
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.
Yeah, but I was saying about is that feels weird to do that setup inside the test
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.
Good work! I think this it's a really great fix and very good addition of test cases :)
Some things to consider:
- use hardcoded values for
assertEqual
- check
machine
status after the first sync in most of the test cases - use
reverse
to create the URLs - remove the
assertNotEqual
since they are not needed - improve the names of the test cases
Finally, another major refactor that we can consider here since most of the test cases share similar code is to use pytest parametrize: https://docs.pytest.org/en/latest/parametrize.html
(I'm not sure if it's possible, though)
stable_version = ( | ||
project.versions | ||
.filter(slug=STABLE, type=type) | ||
.first() |
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.
Instead of .first
you can use .exists
here, since it's exactly what we need.
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.
But we need the object on the next line
readthedocs/restapi/utils.py
Outdated
for version in versions: | ||
version_id = version['identifier'] | ||
version_name = version['verbose_name'] | ||
if version_name == STABLE_VERBOSE_NAME: | ||
has_user_stable = True |
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.
Since we are using has_user_stable
outside this loop, I think it's preferable to create it right before where it's used: line 63 using.
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.
But is still outside the loop, so it's really not right before it's used.
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.
Yes. Is is used inside the loop?
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.
Nop, but the logic that came behind is not related to that code.
def test_normal_behavior_for_stable_after_deleting_user_defined_tag(self): | ||
""" | ||
The user creates a tag named ``stable`` on an existing repo, | ||
when syncing the versions, the RTD's ``stable`` is lost |
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.
is lost (set to machine=False)
here, to be more explicit.
The user creates a tag named ``stable`` on an existing repo, | ||
when syncing the versions, the RTD's ``stable`` is lost | ||
and doesn't update automatically anymore, when the tag is deleted | ||
on the user repository, the RTD's ``stable`` is back. |
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.
same here: is back (set to machine=True)
here, to be more explicit
self.assertEqual( | ||
current_stable.identifier, | ||
version_stable.identifier | ||
) |
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.
Immediately after this, we want to know is that the current_stable.machine
is False
since now it's a version/tag managed by the user.
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.
and the current_stable.identifier
should be 1abc2def3
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.
I believe that is covered by other tests, I'm on the cellphone, so not sure if that is the case
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.
The tests from TestStableVersion
already check that
# 0.8.3 is the current stable | ||
self.assertEqual( | ||
version8.identifier, | ||
current_stable.identifier |
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.
Same here.
self.assertEqual( | ||
current_stable.identifier, | ||
version_stable.identifier | ||
) |
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.
Check for machine status here and use hardcoded identifier.
current_stable = self.pip.get_stable_version() | ||
self.assertEqual( | ||
version8.identifier, | ||
current_stable.identifier, |
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.
Same here.
Also, if we hardcode here the assertNotEqual
is not necessary.
self.assertTrue(version_latest.machine) | ||
|
||
@pytest.mark.xfail(strict=True) | ||
def test_normal_behavior_for_latest_after_deleting_user_defined_branch(self): |
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.
Are we blocked on a decission to make before making this test to pass?
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.
Nope, just trying to understand all cases for stable first
self.pip.get_stable_version().identifier | ||
) | ||
# There arent others stable slugs like stable_a | ||
other_latest = self.pip.versions.filter( |
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.
other_stable?
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.
Ups, copy paste
OK, this is weird... Tests fail after renaming the tests (nothing else change!). Same thing happening on my local instance, if I checkout to a previous commit everything works. Also if I only run the tests for the single file, everything works (on the same commit were the tests fail). |
I think this is something caused by urls collision, the apiv1 and v2 share the same url name and don't have a namespace. |
I did a quick test putting a namespace to the
|
Ok, I have some news... Because the current fetch command doesn't delete untracked tags (only untracked branches), we need to wipe the environment when we delete the duplicated tag (if we delete the duplicated branch, there is no problem). There are some solutions to delete untracked tags (require more than 2 commands). But I find that the newest version of git has the What should I do? I have some ideas to solve this:
I think we want 3 or 4 at the moment and raise an issue to keep track of 1. |
I'm trying to fix the problem by cleaning the current repo in the last commit, tests pass and the user doesn't have to wipe the environment manually, not sure if it's the best way. (I tested this manually too btw) |
We should discuss that in other issue? I don't think there is a quickly solution for that, I mean we can solve the original problem or document this or raise a proper exception when the checkout step fails (but probably the message needs to be generic, I'm not sure, what else can throw an exception here?) |
Agree with you. Let's do 3 and open a new issue for 1. We are moving servers (and upgrading Ubuntu version also) and I'm not really sure how much overhead will introduce to upgrade to a different git version but I don't want to add another thing right now on this server migration.
While testing this manually consider that in production we have 4 build servers. So, one scenario that you want to consider is that your code should not depend on the repo that lives on disk. It could happen that you import a project (that is done by |
I'm trying to change the message here https://github.com/rtfd/readthedocs.org/pull/3913/files#diff-4787d302d24c7ac7a89ad7587dd94007R47 to point the user to wipe the environment, but I'm not sure the best way of doing it, a new user probably doesn't know what |
I feel like we're going down a bit of a rabbit hole here. Let's get this shipped and worry about these small details later :) |
If the user doesn't know, he/she can go to our documentation or finally fill an issue and somebody will help them. As Eric said, don't worry too much about this for now. We will find a better UX later. |
🎆 |
Wow. That was a lot of work. Thanks so much. |
There are several reports of users that somehow ended with the
stable
version stuck on a specific commit, and the only solution is to recreate the project on RTD.I was able to reproduce this issue and other (no relevant, since it can be fixed without recreating the project). Those bugs are documented here #3887.
Here I'm exposing this bug #3887 (comment).
When a user creates a tag named
stable
, the RTD's stable loses itsmachine
attribute, and it can't be recreated (even deleting the tag).This will close #3887, close #534, close #2032, close #1785, close #3041