Skip to content
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

Gitlab integration #44

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

juanjovazquez
Copy link

closes #43

@codecov-io
Copy link

codecov-io commented Oct 17, 2017

Codecov Report

Merging #44 into master will increase coverage by 1.56%.
The diff coverage is 13.92%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #44      +/-   ##
==========================================
+ Coverage   58.52%   60.08%   +1.56%     
==========================================
  Files         134      130       -4     
  Lines        4330     4224     -106     
  Branches      107      121      +14     
==========================================
+ Hits         2534     2538       +4     
+ Misses       1796     1686     -110
Impacted Files Coverage Δ
core/src/main/scala/Github.scala 26.59% <ø> (ø) ⬆️
core/src/main/scala/audit/Auditor.scala 81.81% <ø> (ø) ⬆️
core/src/main/scala/audit/AuditEvent.scala 100% <ø> (ø) ⬆️
core/src/main/scala/Json.scala 0% <0%> (ø) ⬆️
core/src/main/scala/Gitlab.scala 0% <0%> (ø)
core/src/main/scala/Repo.scala 50% <0%> (-23.34%) ⬇️
core/src/main/scala/Released.scala 100% <100%> (ø) ⬆️
core/src/main/scala/storage/h2.scala 82.56% <100%> (ø) ⬆️
http/src/main/scala/plans/Auth.scala 96.42% <100%> (ø) ⬆️
core/src/main/scala/User.scala 100% <100%> (ø) ⬆️
... and 12 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1bf8a4d...ff26ba4. Read the comment docs.

@timperrett
Copy link
Member

@juanjovazquez what's the status of this PR? I would like to label it with a status for admin purposes :-)

@juanjovazquez
Copy link
Author

@timperrett It's almost all covered except releases and webhooks. This week I'll spend some time trying to get these two aspects finished but, as I mentioned in the issue, the releases part changes quite a bit with respect to Github.

My goal so far has been not to be very disruptive with respect to the current code in order to have a first version working as soon as possible. Later, algebra and interpreters could be refactored to better accommodate the three most important scms: Github, Gitlab and Bitbucket.

If you prefer, we could merge after rebasing as it is now in order to tackle what is missing in individual issues. This PR starts to be too big. Please, let me know what works better for you.

@juanjovazquez
Copy link
Author

@timperrett webhooks client api implemented. However, I bumped into another drawback: Gitlab's hooks won't set the User-Agent header. Reported here and looking for a workaround. 😠

@juanjovazquez
Copy link
Author

@timperrett Definitely stuck with the release part. Basically, Gitlab links the concept of release completely to the tag. There is no way to identify the release by itself. And the worst thing is that tags don't have a numerical identifier, but basically the reference as a String, e.g. refs/tags/v1.0.0.

So, my plan is to modify the id type for ReleaseEvent and Release to String. Done this, I'd listen for tags creation events and check if this taghas release notes. In that case, I'd consider it a release.

Quite hacky, but to be honest, I can't find a better way to accommodate this requirement without tackling a profound refactoring. So, if you agree, I'll implement it this way, at least in a first version.

@timperrett
Copy link
Member

@juanjovazquez is there the ability to attach files to a release / tag in GitLab? That's going to be really important so hope it is available (otherwise this might be moot).

@adelbertc @kaiserpelagic can you just chime in with anything you can think of that might cause a problem with releases having a string ID? Provided they never collide then it should be fine. The only drawback might be table indexing, but I dont recall off the top of my head which columns are indexed; im thinking its not a huge problem.

@juanjovazquez
Copy link
Author

@timperrett It's a bit hacky but yes, Gitlab does offer the capability of attaching files to tags as release notes through the web interface. It is hacky because Gitlab just uploads the file generating an GUID for it and adds the url as a yaml comment to the description box. So, it's feasible to retrieve this url from the tag info as release notes. An excerpt of the tag info fetched from the API (see the release section, it's the only we have):

  {
    "commit": {
      "id": "2695effb5807a22ff3d138d593fd856244e155e7",
      "short_id": "2695effb",
      "title": "Initial commit",
      "created_at": "2017-07-26T11:08:53.000+02:00",
      "parent_ids": [
        "2a4b78934375d7f53875269ffd4f45fd83a84ebe"
      ],
      "message": "Initial commit",
      "author_name": "John Smith",
      "author_email": "[email protected]",
      "authored_date": "2012-05-28T04:42:42-07:00",
      "committer_name": "Jack Smith",
      "committer_email": "[email protected]",
      "committed_date": "2012-05-28T04:42:42-07:00"
    },
    "release": {
      "tag_name": "1.0.0",
      "description": "[foo.json](/uploads/<guid>/foo.json)"
    },
    "name": "v1.0.0",
    "message": null
  }

When there's no release, the release section in the json is null. So, at least in theory we might identify whether the creation of some tag involves a release or not.

As for the asset info. I won't be able to provide ID's or other fields like name or state. Just the url and of course the content. I might use dummy values for the rest of fields that are not available.

Anyway, I'd still need to change the ID type for releases in order to use tags with release notes as Nelson releases.

@@ -116,7 +116,7 @@ ALTER TABLE PUBLIC."deployments" ADD CONSTRAINT PUBLIC.CONSTRAINT_F PRIMARY KEY(
CREATE INDEX PUBLIC."deployments_guid_idx" ON PUBLIC."deployments"("guid");
CREATE CACHED TABLE PUBLIC."audit_log"(
"id" BIGINT DEFAULT (NEXT VALUE FOR PUBLIC.SYSTEM_SEQUENCE_15FD08D0_DDC1_4ECB_8FB3_38AB48CE23B4) NOT NULL NULL_TO_DEFAULT SEQUENCE PUBLIC.SYSTEM_SEQUENCE_15FD08D0_DDC1_4ECB_8FB3_38AB48CE23B4,
"release_id" BIGINT,
"release_id" VARCHAR(25),
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICS this is the only change affecting de data model so far as release_id was already defined as VARCHAR(25) in the releases table

Copy link
Contributor

@kaiserpelagic kaiserpelagic Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juanjovazquez we should never be changing an existing migration. If you want to change a DB scheme you should create a new migration. Flyaway uses a numbering convention in the name, so you'd create a filed called V2_1__alter_relase_id.sql where you alter the "audit_log" table.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kaiserpelagic Got it. I'll change it right away.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juanjovazquez it seems like we also need a migration for the releases table.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kaiserpelagic Why is that?. release_id was already a VARCHAR(25) in the releases table.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juanjovazquez interesting, I did not realize that

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kaiserpelagic yep, I got surprise too ;-)

@@ -17,5 +17,6 @@
package nelson

final case class AccessToken(
value: String
value: String,
isPrivate: Boolean = false
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because Gitlab treats OAuth and private personal tokens differently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a sum type instead?

sealed abstract class Token extends Product with Serializable

object Token {
  final case class PersonalToken(...) extends Token
  final case class OAuth(...) extends Token
}

organizationBlacklist = cfg.lookup[List[String]]("organization-blacklist").getOrElse(Nil),
organizationAdminList = cfg.lookup[List[String]]("organization-admins").getOrElse(Nil)
private def readGithub(cfg: KConfig): ScmConfig = {
val service = cfg.lookup[String]("service").getOrElse("github")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service configuration param is used to choose the scm interpreter: Gitlab or GIthub (default).

Copy link
Contributor

@kaiserpelagic kaiserpelagic Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reading configuration for different interpreters I might do something like

kfg.lookup[String]("scm") match {
  case Some("github") => readGithub(kfg.subconfig("github"))
  case Some("gitlab") => readGitlab(kfg.subconfig("gitlab"))
  case _             => None
}

Copy link
Author

@juanjovazquez juanjovazquez Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the time being it's the same configuration.

@juanjovazquez
Copy link
Author

@timperrett I've updated the PR modifying the Id type for Release and ReleaseEvent. Please, tell me whether you're comfortable with this change so that I can finish the implementation. At first sight the change doesn't seem problematic but maybe I missed something.

@@ -395,7 +471,12 @@ object Config {
val nomadcfg = readNomad(cfg.subconfig("nelson.nomad"))

val gitcfg = readGithub(cfg.subconfig("nelson.github"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is configuration of github and gitlab under nelson.github

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, for the time being. Which one is used is determined by the param service, e.g.

service = "gitlab"

Default is github anyway.

I tried not to add many breaking changes in this first version of Gitlab support, but I think that we should re-think the algebra and the configuration to be more generic. Probably in another PR if you agree.

@@ -395,7 +471,12 @@ object Config {
val nomadcfg = readNomad(cfg.subconfig("nelson.nomad"))

val gitcfg = readGithub(cfg.subconfig("nelson.github"))
val git = new Github.GithubHttp(gitcfg, http0)
val git: GithubOp ~> Task = gitcfg match {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use something other than GithubOp now

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same idea as before. I left that kind of changes for a second review.


case GetUserRepositories(t: AccessToken) =>
def go(uri: String)(accum: List[Repo]): List[Repo] = {
val EntityWithMeta(repos, pagination) = authFetchWithMeta[List[Repo]](uri, t).run
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should never be calling .run in code like this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, it's basically the same thing as in the Github interpreter. I'll have it a look anyway.

@juanjovazquez juanjovazquez changed the title WIP Gitlab integration Gitlab integration Jan 10, 2018
@@ -505,12 +509,22 @@ object Json {
e <- (z --\ "repository" --\ "id").as[Long]
} yield {
Github.ReleaseEvent(
id = a,
id = a.toString,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not decode it as a String above, instead of calling toString here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, take it for granted.

@@ -30,7 +30,7 @@ final case class Released(
/* when was this release created */
timestamp: Instant,
/* reference id from github */
releaseId: Long,
releaseId: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a String now? does Gitlab not represent it was a number?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, it's not the case. Gitlab has no releases, just tags, and these have no numeric ids either. 😞

@juanjovazquez juanjovazquez force-pushed the wip-gitlab-support branch 2 times, most recently from ab9f2e9 to 61158e6 Compare January 15, 2018 11:41
Copy link
Member

@adelbertc adelbertc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you want to merge this as is or just put it up for review? I think it'd also be good to get changes that others suggested in, like renaming GithubOp to something more generic, etc.

Perhaps those can be made in a separate commit so it's easy to revert if you're concerned about touching too many things.

--: limitations under the License.
--:
--: ----------------------------------------------------------------------------
ALTER TABLE PUBLIC."audit_log" ALTER COLUMN "release_id" VARCHAR(25);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familiar with DB migrations, this will probably need @timperrett 's eyes.

@@ -17,5 +17,6 @@
package nelson

final case class AccessToken(
value: String
value: String,
isPrivate: Boolean = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a sum type instead?

sealed abstract class Token extends Product with Serializable

object Token {
  final case class PersonalToken(...) extends Token
  final case class OAuth(...) extends Token
}

case _: ScmConfig.GithubConfig =>
new Github.GithubHttp(gitcfg, http0)
case _ =>
new Gitlab.GitlabHttp(gitcfg, http4sClient(timeout))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Picky but I generally prefer pat mat instead of type casing, if only for theoretical reasons described here: https://typelevel.org/blog/2014/11/10/why_is_adt_pattern_matching_allowed.html

Also perhaps get rid of _ and do an explicit match on GitLab's constructor so any potential future additions error here as they should.

@@ -226,7 +226,7 @@ object Github {
}
}

final class GithubHttp(cfg: GithubConfig, http: dispatch.Http) extends (GithubOp ~> Task) {
final class GithubHttp(cfg: ScmConfig, http: dispatch.Http) extends (GithubOp ~> Task) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmmmm this is a bit bothersome. On one hand I don't like using subtypes for data types that are ADTs on the other hand the only config this should be called with is the GithubConfig.. I would learn towards using the subtype anyways.

@@ -76,13 +76,13 @@ object Github {
) extends Event

final case class ReleaseEvent(
id: Long,
id: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One trick we can try is parameterize it into ReleaseEvent[A] so we have ReleaseEvent[Long] and ReleaseEvent[String].. wdyt? @timperrett @kaiserpelagic

DecodeJson(c => (c --\ "access_token").as[String]).map(AccessToken.apply(_))

implicit lazy val AccessTokenEncoder: EncodeJson[AccessToken] =
jencode1L((t: AccessToken) => t.value)("access_token")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gitlab integration
5 participants