Skip to content

Commit dfcc9e6

Browse files
rokroskarjsam
authored andcommitted
fix: use UI-resolved project path as project ID (#701)
* fix: use UI-resolved project path as project ID * fix: removes the duplicate method from a bad merge
1 parent 0d6536d commit dfcc9e6

File tree

3 files changed

+90
-49
lines changed

3 files changed

+90
-49
lines changed

renku/core/management/repository.py

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -133,45 +133,9 @@ def cwl_prefix(self):
133133
self.workflow_path.mkdir(parents=True, exist_ok=True) # for Python 3.5
134134
return str(self.workflow_path.resolve().relative_to(self.path))
135135

136-
@property
137-
def project_id(self):
138-
"""Return the id for the project based on the repo origin remote."""
139-
from renku.core.models.git import GitURL
140-
141-
remote_name = 'origin'
142-
try:
143-
remote_branch = self.repo.head.reference.tracking_branch()
144-
if remote_branch is not None:
145-
remote_name = remote_branch.remote_name
146-
except TypeError:
147-
pass
148-
149-
try:
150-
url = GitURL.parse(self.repo.remotes[remote_name].url)
151-
152-
# Remove gitlab. unless running on gitlab.com.
153-
hostname_parts = url.hostname.split('.')
154-
if len(hostname_parts) > 2 and hostname_parts[0] == 'gitlab':
155-
hostname_parts = hostname_parts[1:]
156-
url = attr.evolve(url, hostname='.'.join(hostname_parts))
157-
except IndexError:
158-
url = None
159-
160-
if url:
161-
remote_url = 'https://' + url.hostname
162-
163-
if url.owner:
164-
remote_url += '/' + url.owner
165-
if url.name:
166-
remote_url += '/' + url.name
167-
168-
return remote_url
169-
170-
return 'file://{0}'.format(self.path)
171-
172136
@cached_property
173137
def project(self):
174-
"""Return the FOAF/PROV representation of the project."""
138+
"""Return the Project instance."""
175139
if self.renku_metadata_path.exists():
176140
return Project.from_yaml(self.renku_metadata_path, client=self)
177141

@@ -365,16 +329,15 @@ def with_commit(self, commit):
365329
self.repo.git.checkout(current_commit)
366330

367331
@contextmanager
368-
def with_metadata(self, read_only=False):
332+
def with_metadata(self, read_only=False, name=None):
369333
"""Yield an editable metadata object."""
370334
metadata_path = self.renku_metadata_path
371335

372336
if metadata_path.exists():
373337
metadata = Project.from_yaml(metadata_path, client=self)
374338
else:
375-
metadata = Project.from_jsonld({},
376-
client=self,
377-
__reference__=metadata_path)
339+
metadata = Project(name=name, client=self)
340+
metadata.__reference__ = metadata_path
378341

379342
yield metadata
380343

@@ -451,8 +414,7 @@ def init_repository(self, name=None, force=False):
451414
) + '\n'
452415
)
453416

454-
with self.with_metadata() as metadata:
455-
metadata.name = name
417+
with self.with_metadata(name=name) as metadata:
456418
metadata.updated = datetime.now(timezone.utc)
457419

458420
return str(path)

renku/core/models/projects.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"""Model objects representing projects."""
1919

2020
import datetime
21+
import os
2122

2223
import attr
2324

@@ -26,6 +27,8 @@
2627
from renku.core.models.datastructures import Collection
2728
from renku.core.utils.datetime8601 import parse_date
2829

30+
PROJECT_URL_PATH = 'projects'
31+
2932

3033
@jsonld.s(
3134
type=[
@@ -65,7 +68,14 @@ class Project(object):
6568

6669
client = attr.ib(default=None, kw_only=True)
6770

68-
creator = jsonld.ib(default=None, kw_only=True, context='schema:creator')
71+
creator = jsonld.ib(
72+
default=None,
73+
kw_only=True,
74+
context={
75+
'@id': 'schema:creator',
76+
'@type': 'schema:Person',
77+
},
78+
)
6979

7080
_id = jsonld.ib(context='@id', kw_only=True, default=None)
7181

@@ -88,8 +98,32 @@ def __attrs_post_init__(self):
8898
# this assumes the project is being newly created
8999
self.creator = Creator.from_git(self.client.repo)
90100

91-
if not self._id and self.client:
92-
self._id = self.client.project_id
101+
self._id = self.project_id
102+
103+
@property
104+
def project_id(self):
105+
"""Return the id for the project based on the repo origin remote."""
106+
import pathlib
107+
import urllib
108+
109+
# Determine the hostname for the resource URIs.
110+
# If RENKU_DOMAIN is set, it overrides the host from remote.
111+
# Default is localhost.
112+
host = 'localhost'
113+
owner = self.creator.email.split('@')[0] if self.creator else 'NULL'
114+
name = self.name
115+
116+
if self.client:
117+
remote = self.client.remote
118+
host = self.client.remote.get('host') or host
119+
owner = remote.get('owner') or owner
120+
name = remote.get('name') or name
121+
host = os.environ.get('RENKU_DOMAIN') or host
122+
project_url = urllib.parse.urljoin(
123+
'https://{host}'.format(host=host),
124+
pathlib.posixpath.join(PROJECT_URL_PATH, owner, name or 'NULL')
125+
)
126+
return project_url
93127

94128

95129
class ProjectCollection(Collection):
Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# See the License for the specific language governing permissions and
1717
# limitations under the License.
1818
"""Test projects API."""
19-
19+
import os
2020
from datetime import datetime, timezone
2121

2222
import pytest
@@ -110,7 +110,8 @@ def test_project_serialization():
110110

111111
context = data['@context']
112112
assert 'schema:name' == context['name']
113-
assert 'schema:creator' == context['creator']
113+
assert 'schema:creator' == context['creator'].get('@id')
114+
assert 'schema:Person' == context['creator'].get('@type')
114115
assert 'schema:dateUpdated' == context['updated']
115116
assert 'schema:dateCreated' == context['created']
116117
assert 'schema:schemaVersion' == context['version']
@@ -135,7 +136,8 @@ def test_project_metadata_compatibility(project_meta, version, is_broken):
135136
assert 'demo' == project.name
136137

137138
assert 'schema:name' == project._jsonld_context['name']
138-
assert 'schema:creator' == project._jsonld_context['creator']
139+
assert 'schema:creator' == project._jsonld_context['creator'].get('@id')
140+
assert 'schema:Person' == project._jsonld_context['creator'].get('@type')
139141
assert 'schema:dateUpdated' == project._jsonld_context['updated']
140142
assert 'schema:dateCreated' == project._jsonld_context['created']
141143
assert 'schema:schemaVersion' == project._jsonld_context['version']
@@ -181,3 +183,46 @@ def test_project_creator_deserialization(client, project):
181183
# now the creator should be the one from the commit
182184
project = Project.from_yaml(client.renku_metadata_path, client=client)
183185
assert project.creator.email == '[email protected]'
186+
187+
188+
def test_project_uri(client, project, monkeypatch):
189+
"""Test that the project URI is correctly formed."""
190+
from git.refs import RemoteReference
191+
from git.refs.head import Head
192+
193+
# 1. the simple case where no other hostname exists
194+
assert client.project._id.startswith('https://localhost')
195+
196+
# use the RENKU_DOMAIN environment variable to override localhost
197+
with monkeypatch.context() as monkey:
198+
monkey.setenv('RENKU_DOMAIN', 'renku.ch')
199+
project = Project.from_yaml(client.renku_metadata_path, client=client)
200+
assert project._id.startswith('https://renku.ch')
201+
202+
# 2. set up the master remote to be at https://example.com
203+
# This should yield a project id that starts with https://example.com
204+
host = 'example.com'
205+
client.repo.git.remote(
206+
'add', 'origin', 'https://{host}/namespace/{name}.git'.format(
207+
host=host, name=client.project.name
208+
)
209+
)
210+
211+
def mock_tracking():
212+
return RemoteReference('refs/remotes/origin/master')
213+
214+
with monkeypatch.context() as monkey:
215+
monkey.setattr(Head, 'tracking_branch', mock_tracking)
216+
project = Project.from_yaml(client.renku_metadata_path, client=client)
217+
project_id = 'https://{host}/projects/namespace/{name}'.format(
218+
host=host, name=client.project.name
219+
)
220+
assert project._id == project_id
221+
222+
# use the RENKU_DOMAIN environment variable to override remote
223+
monkey.setenv('RENKU_DOMAIN', 'renku.ch')
224+
project = Project.from_yaml(client.renku_metadata_path, client=client)
225+
project_id = 'https://{host}/projects/namespace/{name}'.format(
226+
host=os.environ.get('RENKU_DOMAIN'), name=client.project.name
227+
)
228+
assert project._id == project_id

0 commit comments

Comments
 (0)