tsoding / issuestant Goto Github PK
View Code? Open in Web Editor NEWIssue tracker assistant
License: MIT License
Issue tracker assistant
License: MIT License
README does not describe how exactly the thing helps with issues.
Add some basic build instructions to the README.
Starting from 0.17
Let's use https://github.com/tsoding/Issuestant as the source of data. Only this repo should available for building a split forest from for now.
/api/splitforest/<usr-or-org>/<repo>
API call (only /api/splitforest/tsoding/issuestant
should work for now)/api/splitforest/tsoding/issuestant
should return serialized Split Forest for issues of https://github.com/tsoding/Issuestant. To achive that just serialize list of SplitIssueTree with circe (we already depend on it)I believe that before even working on #20 or #19 we have to develop that core behavior framework first. @ForNeVeR already did a pretty good job on formalizing his ideas about it. Thanks to him! Let's continue discussing that here.
Split from #1
Split from #1
$ sbt run
An exception
org.http4s.MalformedMessageBodyFailure: Malformed request body: Invalid JSON
at org.http4s.jawn.JawnInstances$$anonfun$jawnDecoder$1$$anonfun$apply$1.applyOrElse(JawnInstances.scala:16) ~[http4s-jawn_2.11-0.15.6.jar:0.15.6]
at org.http4s.jawn.JawnInstances$$anonfun$jawnDecoder$1$$anonfun$apply$1.applyOrElse(JawnInstances.scala:14) ~[http4s-jawn_2.11-0.15.6.jar:0.15.6]
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:223) ~[scala-library-2.11.8.jar:1.0.0-M1]
at scala.PartialFunction$Lifted.apply(PartialFunction.scala:219) ~[scala-library-2.11.8.jar:1.0.0-M1]
at scalaz.stream.Process$$anonfun$partialAttempt$1.apply(Process.scala:392) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$partialAttempt$1.apply(Process.scala:392) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$attempt$1$$anonfun$apply$22.apply(Process.scala:230) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$attempt$1$$anonfun$apply$22.apply(Process.scala:230) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$attempt$1.apply(Process.scala:230) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$attempt$1.apply(Process.scala:229) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12$$anonfun$apply$13.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12$$anonfun$apply$13.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.Trampoline$$anonfun$delay$1.apply(Free.scala:262) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Trampoline$$anonfun$delay$1.apply(Free.scala:262) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go2$1(Free.scala:134) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go(Free.scala:137) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.run(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.go$1(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.step(Process.scala:97) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$Append.step(Process.scala:641) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$pipe$1.apply(Process.scala:143) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$pipe$1.apply(Process.scala:139) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$flatMap$1.apply(Process.scala:46) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$flatMap$1.apply(Process.scala:46) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.flatMap(Process.scala:46) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$Emit.flatMap(Process.scala:592) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$flatMap$4.apply(Process.scala:48) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$flatMap$4.apply(Process.scala:48) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.Free$$anonfun$map$1.apply(Free.scala:53) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$map$1.apply(Free.scala:53) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.scalaz$Free$$fastFlatMap(Free.scala:72) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$scalaz$Free$$fastFlatMap$1.apply(Free.scala:73) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$scalaz$Free$$fastFlatMap$1.apply(Free.scala:73) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.std.FunctionInstances$$anon$1$$anonfun$map$1.apply(Function.scala:56) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go2$1(Free.scala:134) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go(Free.scala:137) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.run(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.go$1(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.step(Process.scala:97) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$Append.step(Process.scala:641) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.go$3(Process.scala:482) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$3$3.apply(Process.scala:490) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$3$3.apply(Process.scala:490) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.concurrent.Task$$anonfun$flatMap$1$$anonfun$1.apply(Task.scala:36) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Task$$anonfun$flatMap$1$$anonfun$1.apply(Task.scala:36) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Task$.Try(Task.scala:403) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Task$$anonfun$flatMap$1.apply(Task.scala:36) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Task$$anonfun$flatMap$1.apply(Task.scala:34) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scala.Function1$$anonfun$andThen$1.apply(Function1.scala:52) ~[scala-library-2.11.8.jar:1.0.0-M1]
at scala.Function1$$anonfun$andThen$1.apply(Function1.scala:52) ~[scala-library-2.11.8.jar:1.0.0-M1]
at scalaz.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:58) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:58) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future.step(Future.scala:109) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future.listen(Future.scala:75) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future$$anonfun$listen$1$$anonfun$apply$4.apply(Future.scala:79) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future$$anonfun$listen$1$$anonfun$apply$4.apply(Future.scala:79) ~[scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$map$1.apply(Free.scala:53) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$map$1.apply(Free.scala:53) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.scalaz$Free$$fastFlatMap(Free.scala:72) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$resume$1.apply(Free.scala:88) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$resume$1.apply(Free.scala:88) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.std.FunctionInstances$$anon$1$$anonfun$map$1.apply(Function.scala:56) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go2$1(Free.scala:134) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go(Free.scala:137) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.run(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future$$anonfun$apply$15$$anon$4.call(Future.scala:380) [scalaz-concurrent_2.11-7.1.11.jar:na]
at scalaz.concurrent.Future$$anonfun$apply$15$$anon$4.call(Future.scala:380) [scalaz-concurrent_2.11-7.1.11.jar:na]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_76]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_76]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_76]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_76]
Caused by: jawn.ParseException: exhausted input
at jawn.AsyncParser.churn(AsyncParser.scala:234) ~[jawn-parser_2.11-0.10.4.jar:0.10.4]
at jawn.AsyncParser.finish(AsyncParser.scala:98) ~[jawn-parser_2.11-0.10.4.jar:0.10.4]
at jawnstreamz.package$$anonfun$parseJson$1$$anonfun$apply$2.apply(package.scala:31) ~[jawn-streamz_2.11-0.10.1.jar:0.10.1]
at jawnstreamz.package$$anonfun$parseJson$1$$anonfun$apply$2.apply(package.scala:31) ~[jawn-streamz_2.11-0.10.1.jar:0.10.1]
at scalaz.stream.Process$$anonfun$onComplete$1.apply(Process.scala:338) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$onComplete$1.apply(Process.scala:338) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12$$anonfun$apply$13.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12$$anonfun$apply$13.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.Trampoline$$anonfun$delay$1.apply(Free.scala:262) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Trampoline$$anonfun$delay$1.apply(Free.scala:262) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free$$anonfun$run$1.apply(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go2$1(Free.scala:134) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.go(Free.scala:137) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Free.run(Free.scala:187) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.go$1(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.step(Process.scala:97) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$Append.step(Process.scala:641) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.disconnect(Process.scala:247) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$Append.disconnect(Process.scala:641) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$disconnect$2.apply(Process.scala:249) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$disconnect$2.apply(Process.scala:249) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$suspend$1.apply(Process.scala:1498) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$suspend$1.apply(Process.scala:1497) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$go$1$1.apply(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.go$1(Process.scala:84) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$class.step(Process.scala:97) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$Append.step(Process.scala:641) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$suspendStep$1.apply(Process.scala:106) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$suspendStep$1.apply(Process.scala:105) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12$$anonfun$apply$13.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12$$anonfun$apply$13.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Util$.Try(Util.scala:38) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.stream.Process$$anonfun$2$$anonfun$apply$12.apply(Process.scala:115) ~[scalaz-stream_2.11-0.8.6.jar:na]
at scalaz.Trampoline$$anonfun$delay$1.apply(Free.scala:262) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.Trampoline$$anonfun$delay$1.apply(Free.scala:262) ~[scalaz-core_2.11-7.1.11.jar:na]
at scalaz.std.FunctionInstances$$anon$1$$anonfun$map$1.apply(Function.scala:56) ~[scalaz-core_2.11-7.1.11.jar:na]
... 70 common frames omitted
No exceptions
I think we close the connection on each iteration of etag polling. But I'm not sure about that. We have to investigate that.
Split from #20
TODO 19e120b5-c7a8-426e-b54c-170cf1d7d3da
It's actually not a trivial task, probably requires some decomposition. That's why it's a separate issues.
Derived from #30 (comment)
Split from #18
Just implement initial architecture for REST API.
https://<issuestant-site>/api/*
,/api/hello
that answers something like { "message": "hello" }
in application/json
/api/splitforest/tsoding/issuestant
REST API call.Consider the following use case.
.travis.yml
Split from #38
TODO e4581c14-8db7-4e1b-90f0-0b8faec52a33
Extract ETag from the previousResponse and use it for polling the next events
Right now on each HTTP request during ETAG polling we get the following bunch of lines.
13:30:40.030 [pool-8-thread-3] DEBUG org.http4s.blaze.pipeline.Stage - Beginning request: GET https://api.github.com/repos/tsoding/issuestant-playground/issues/events
13:30:40.264 [anInnocuousThread] DEBUG org.http4s.blaze.pipeline.Stage - SSL Read Request Status: Status = OK HandshakeStatus = NOT_HANDSHAKING
bytesConsumed = 862 bytesProduced = 833, java.nio.HeapByteBuffer[pos=833 lim=16921 cap=16921]
13:30:40.264 [anInnocuousThread] DEBUG org.http4s.blaze.pipeline.Stage - SSL Read Request Status: Status = BUFFER_UNDERFLOW HandshakeStatus = NOT_HANDSHAKING
bytesConsumed = 0 bytesProduced = 0, java.nio.HeapByteBuffer[pos=0 lim=16921 cap=16921]
13:30:40.264 [anInnocuousThread] DEBUG org.http4s.blaze.pipeline.Stage - SSL Read Request Status: Status = BUFFER_UNDERFLOW HandshakeStatus = NOT_HANDSHAKING
bytesConsumed = 0 bytesProduced = 0, java.nio.HeapByteBuffer[pos=0 lim=16921 cap=16921]
13:30:40.265 [http4s-blaze-client-5] DEBUG org.http4s.blaze.pipeline.Stage - Resetting org.http4s.client.blaze.Http1Connection after completing request.
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.blaze.pipeline.Stage - ClientTimeoutStage shutting down at Sat Aug 05 13:30:40 NOVT 2017
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.client.PoolManager - Recycling connection: allocated=1 idleQueue.size=0 waitQueue.size=0
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.client.PoolManager - Returning idle connection to pool: allocated=1 idleQueue.size=0 waitQueue.size=0
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.client.PoolManager - Requesting connection: allocated=1 idleQueue.size=1 waitQueue.size=0
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.client.PoolManager - Recycling connection: allocated=1 idleQueue.size=0 waitQueue.size=0
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.blaze.pipeline.Stage - ClientTimeoutStage starting up at Sat Aug 05 13:30:40 NOVT 2017
13:30:40.265 [pool-8-thread-4] DEBUG org.http4s.blaze.pipeline.Stage - Connection was idle. Running.
The only useful information it tells is that there was an HTTP request to https://api.github.com/repos/tsoding/issuestant-playground/issues/events
. That's it.
I'm not really interested in each an individual HTTP request. I'm more interested in already happend GitHub events. Let's config logback to log only that.
Wartremover looks like a nice tool. Let's try it out! It should perform the check on CI, of course. I think while the project is small it should be relatively easy to enforce any kind of linting and static checks.
Right now it's just a YAML file with the API specification. Anyone can use it however they want. I'd like to improve this experience somehow. For example,
Any other ideas are welcome.
Issuestant should automatically (or with configuration) detect where the project store the copyright year, and should be able to update copyright after any commit is made in the next year.
@Issuestant should automatically replace all of the dynamic src-links with the permanent ones with the current latest commit hash. For example:
https://github.com/tsoding/Issuestant/blob/master/src/main/scala/me/rexim/Mixer.scala
should be replaced with
https://github.com/tsoding/Issuestant/blob/<latest-commit-hash>/src/main/scala/me/rexim/Mixer.scala
That feature will require to give @Issuestant enough permissions to edit all of the comments and descriptions in a project. If after enabling that feature (somehow, we need to come up with a specific mechanism for enabling features, maybe via filing an issue) @Issuestant doesn't have enough permissions, he should file an issue about that and assign it to the Project Leader for resolution.
Split from #1
The build is slow because of the lack of one
This issue has been split in #21
I should be able somehow to tell (hardcode is ok at the moment) to Issuestant to gather all of the issues from a project, analyse their split links, build a split tree and visualize it on the Issuestant's web UI. Manual request to update the tree is ok at the moment.
Split tree is a tree where each node is an issue. Issues that contain Split from # in there description are considered to be children of issue . It's more correct to call that "Split forest", because there is no single root. But creating artificial root is ok. Could be just the name of the project.
If issue ForNeVeR/Jabber-Net#2 contains Split from #1
in the description, the split tree will look like:
ForNeVeR/Jabber-Net#1
|\
| ForNeVeR/Jabber-Net#2
.
.
Heroku shuts down unused instances. We can organize some kind of heartbeat from my personal VPS (which I don't wanna use for hosting because of the limited resources) to wake Issuestant up until we have enough resources for a better hosting.
Split from #5
Split from #5
Heroku asks use to implement this https://devcenter.heroku.com/articles/scala-support#build-behavior
Here is what I was thinking of during the stream. I made events
an infinite list that follows a precise pattern (with delay
being the shift in time where the pattern repeats.)
module Main where
type Timestamp = Int
type Event = (Timestamp,String)
type Response = (Timestamp,[Event])
-- with delay >7 the next iteration of responses is completely disjoint
-- with 1..6 part of the new cascade overlaps and only a tail is actually new
delay = 10
events :: [Response]
events = [
(0, [ (1,"A"),(2,"B"),(3,"C") ]),
(4, [ (1,"A"),(2,"B"),(3,"C"),(4,"D") ]),
(5, [ (3,"C"),(4,"D") ]),
(6, [ (3,"C"),(4,"D"),(6,"E") ]),
(7, [ (4,"D"),(6,"E"),(7,"F") ])
] ++
map (\(x,y) -> (x+delay, map (\(z,w) -> (z+delay,w)) y)) events
main = print $ take 20 filteredEvents
filteredEvents = concat $ map snd $ scanl collect (0, []) events
-- to see how this data structure is similar to yours you can try instead:
-- filteredEvents = scanl collect (0, []) events
collect :: (Timestamp, [Event]) -> Response -> (Timestamp, [Event])
collect (min_t, _) (t, es)
| length news > 0 = (new_t, news)
| otherwise = (min_t, [] )
where
news = filter (\(t, _) -> t > min_t) es
new_t = maximum . map fst $ news -- protected by the guard length news > 0
Examples:
-- delay = 10
[(1,"A"),(2,"B"),(3,"C"),(4,"D"),(6,"E"),(7,"F"),(11,"A"),(12,"B"),(13,"C"),(14,"D"),(16,"E"),(17,"F"),(21,"A"),(22,"B"),(23,"C"),(24,"D"),(26,"E"),(27,"F"),(31,"A"),(32,"B")]
-- delay = 1
[(1,"A"),(2,"B"),(3,"C"),(4,"D"),(6,"E"),(7,"F"),(8,"F"),(9,"F"),(10,"F"),(11,"F"),(12,"F"),(13,"F"),(14,"F"),(15,"F"),(16,"F"),(17,"F"),(18,"F"),(19,"F"),(20,"F"),(21,"F")]
-- delay = 5
[(1,"A"),(2,"B"),(3,"C"),(4,"D"),(6,"E"),(7,"F"),(8,"C"),(9,"D"),(11,"E"),(12,"F"),(13,"C"),(14,"D"),(16,"E"),(17,"F"),(18,"C"),(19,"D"),(21,"E"),(22,"F"),(23,"C"),(24,"D")]
-- delay = 6
[(1,"A"),(2,"B"),(3,"C"),(4,"D"),(6,"E"),(7,"F"),(8,"B"),(9,"C"),(10,"D"),(12,"E"),(13,"F"),(14,"B"),(15,"C"),(16,"D"),(18,"E"),(19,"F"),(20,"B"),(21,"C"),(22,"D"),(24,"E")]
I also wonder if it can be improved / simplified further.
Update: oops I was shadowing Prelude.last
Update 2: another idea, in case one doesn't want to lose the information about the grouping of events from the api, instead of concat
:
-- delay = 6
-- filteredEvents = filter (not . null) $ map snd $ scanl collect (0, []) events
[[(1,"A"),(2,"B"),(3,"C")],[(4,"D")],[(6,"E")],[(7,"F")],[(8,"B"),(9,"C")],[(10,"D")],[(12,"E")],[(13,"F")],[(14,"B"),(15,"C")],[(16,"D")],[(18,"E")],[(19,"F")],[(20,"B"),(21,"C")],[(22,"D")],[(24,"E")],[(25,"F")],[(26,"B"),(27,"C")],[(28,"D")],[(30,"E")],[(31,"F")]]
Split from #20
Introduced in #41
TODO(#42)
May supersede #37
The Permalink service should be essentially an FSM. The full set of the possible states of such FSM should be represented by ADT. For example
sealed trait PermalinkProtocol {
def handleEvent(event: Event): PermalinkProtocol
}
case class PermalinkServingState(..) extends PermalinkProtocol
case class PernalinkAskPermissionState(..) extends PermalinkProtocol
Issuestant should be able to increment project version. I imagine two modes:
pom.xml
, build.gradle
, AssemblyInfo.*
, package.json
; probably appveyor.yml
)semver:major
were implemented, it should bump major version number) (I think Node.js guys have automation and GitHub tag layout for this task; check it if interested)Don't forget to introduce dependencies that enable Permalink with modifying comments, modifying issue descriptions and fileing issues.
The Permalink service should be essentially an FSM. The full set of the possible states of such FSM should be represented by ADT. For example
sealed trait PermalinkProtocol {
def handleEvent(event: Event): PermalinkProtocol
}
case class PermalinkServingState(..) extends PermalinkProtocol
case class PernalinkAskPermissionState(..) extends PermalinkProtocol
Once auto deploy is done I'd like to have some notifications in my email about that.
Split from #38
Introduced in #49
TODO(#51)
Implement some kind of test utility that enables you with taking a sequence of response and converting it into a client that can be fed into EtagPolling
. That will make the testing of this class way easier.
Here is the client http://http4s.org/v0.15/api/org/http4s/client/Client.html Basically it's a wrapper over a Service
which is just a function from a request to a response.
Split from #20
TODO e2419ff0-47b9-4a54-91db-979b84de030e
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.