payload: {"action":"created","comment":{"url":"https://api.github.com/repos/loadimpact/k6/pulls/comments/333403958","pull_request_review_id":299914410,"id":333403958,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDMzMzQwMzk1OA==","diff_hunk":"@@ -0,0 +1,341 @@\n+/*\n+ *\n+ * k6 - a next-generation load testing tool\n+ * Copyright (C) 2019 Load Impact\n+ *\n+ * This program is free software: you can redistribute it and/or modify\n+ * it under the terms of the GNU Affero General Public License as\n+ * published by the Free Software Foundation, either version 3 of the\n+ * License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU Affero General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Affero General Public License\n+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n+ *\n+ */\n+\n+package lib\n+\n+import (\n+\t\"context\"\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"sort\"\n+\t\"strings\"\n+\t\"sync\"\n+\t\"time\"\n+\n+\t\"github.com/loadimpact/k6/stats\"\n+\t\"github.com/loadimpact/k6/ui/pb\"\n+\t\"github.com/sirupsen/logrus\"\n+\tnull \"gopkg.in/guregu/null.v3\"\n+)\n+\n+//TODO: remove globals and use some type of explicit dependency injection?\n+//nolint:gochecknoglobals\n+var (\n+\texecutorConfigTypesMutex   sync.RWMutex\n+\texecutorConfigConstructors = make(map[string]ExecutorConfigConstructor)\n+)\n+\n+// ExecutionStep is used by different executors to specify the planned number\n+// of VUs they will need at a particular time. The times are relative to their\n+// StartTime, i.e. they don't take into account the specific starting time of\n+// the executor, as that will be considered by the external execution executor\n+// separately.\n+//\n+// A slice [{t1, v1}, {t2, v2}, {t3, v3}, ..., {tn, vn}] of execution steps\n+// means that a executor will need 0 VUs until t1, it will need v1 number of\n+// VUs from time t1 until t2, need v2 number of VUs from time t2 to t3, and so\n+// on. t1 is usually 0, tn is usually the same as GetMaxDuration() and vn is\n+// usually 0.\n+//\n+// Keep in mind that t(i) may be exactly equal to t(i+i), when there's an abrupt\n+// transition in the number of VUs required by a executor. For example, the\n+// variable-looping-vus executor may have 0-duration stages, or it may scale up\n+// VUs in its last stage right until the end. These\n+//\n+// []ExecutionStep is also used by the ExecutorConfigMap, to represent the\n+// amount of needed VUs among all executors, during the whole execution of a\n+// test script. In that context, each executor's StartTime is accounted for and\n+// included in the offsets.\n+type ExecutionStep struct {\n+\tTimeOffset      time.Duration\n+\tPlannedVUs      uint64\n+\tMaxUnplannedVUs uint64\n+}\n+\n+//TODO: make []ExecutionStep or []ExecutorConfig their own type?\n+\n+// ExecutorConfig is an interface that should be implemented by all executor config types","path":"lib/executors.go","position":74,"original_position":74,"commit_id":"5700ea66849ff84904bd22df8cba140935761de6","original_commit_id":"5700ea66849ff84904bd22df8cba140935761de6","user":{"login":"imiric","id":1009277,"node_id":"MDQ6VXNlcjEwMDkyNzc=","avatar_url":"https://avatars1.githubusercontent.com/u/1009277?v=4","gravatar_id":"","url":"https://api.github.com/users/imiric","html_url":"https://github.com/imiric","followers_url":"https://api.github.com/users/imiric/followers","following_url":"https://api.github.com/users/imiric/following{/other_user}","gists_url":"https://api.github.com/users/imiric/gists{/gist_id}","starred_url":"https://api.github.com/users/imiric/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/imiric/subscriptions","organizations_url":"https://api.github.com/users/imiric/orgs","repos_url":"https://api.github.com/users/imiric/repos","events_url":"https://api.github.com/users/imiric/events{/privacy}","received_events_url":"https://api.github.com/users/imiric/received_events","type":"User","site_admin":false},"body":"> The biggest reason is ExecutorConfigMap, i.e. the map[string]ExecutorConfig type we use to parse and validate the execution option. Having this interface allows us to automagically unmarshal the very different configs in the single data structure, and then validate them and treat them together in the rest of the codebase, not caring about their specific types one jot.\r\n\r\nThat is a compelling use case, and I see why you did it that way.\r\n\r\nI still think configuration should be \"dumber\" (set/get only), and not tied to a particular app or functionality.\r\n\r\n\r\n> In my mind, most of the methods in this interface are about querying information about an executor config - after all, that's the things users will specify in the execution options.\r\n\r\nTrue, you can look at it that way. For me configuration is something best handled once up front / on startup in a generic way, and then passed on to (or read by) different components that need it. It shouldn't be critical to the application besides being an in-memory key-value store.\r\n\r\nWhich is why I see `NewExecutor()` and `GetExecutionRequirements()` as being outside the responsibility of a configuration type.\r\n\r\nIn my ideal design, the pseudo-lifecycle would be something like:\r\n\r\n1. `k6/cmd` gathers config sources, assembles a `k6.config.Config` object, and validates it.\r\n2. `k6/engine` or `k6/execution` receives a validated `Config`, walks through `Config.Execution` and instantiates the required executors into an `ExecutorMap` or similar.\r\n3. `ExecutorMap` is used the same way as `ExecutorConfigMap` is currently, without configuration being a runtime requirement. So all current `GetName()`, `GetStartTime()`, etc. methods will be retrieved from the already configured executor instance itself.\r\n\r\nThis would require an overhaul of the current config system, but if we restructured only what's required for the new executors in this way, it could serve as a blueprint for the config refactor we could expand on later.\r\n\r\n> since we need to know whether a particular executor is distributable before we initialize it\r\n\r\nI see, and agree that it would make more sense for this to be a static method, but I would still prefer having an `instance.isDistributable()` check in the constructor, than handling it with a specific configuration type.\r\n\r\n\r\nNot sure, this would be a lot of work to refactor currently, but it would bother me if we have a clean `k6/config` package one day that parts of the configuration is being validated and used as a functional requirement in other parts of the codebase.","created_at":"2019-10-10T08:57:53Z","updated_at":"2019-10-10T08:57:54Z","html_url":"https://github.com/loadimpact/k6/pull/1007#discussion_r333403958","pull_request_url":"https://api.github.com/repos/loadimpact/k6/pulls/1007","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/loadimpact/k6/pulls/comments/333403958"},"html":{"href":"https://github.com/loadimpact/k6/pull/1007#discussion_r333403958"},"pull_request":{"href":"https://api.github.com/repos/loadimpact/k6/pulls/1007"}},"in_reply_to_id":330459699},"pull_request":{"url":"https://api.github.com/repos/loadimpact/k6/pulls/1007","id":272772661,"node_id":"MDExOlB1bGxSZXF1ZXN0MjcyNzcyNjYx","html_url":"https://github.com/loadimpact/k6/pull/1007","diff_url":"https://github.com/loadimpact/k6/pull/1007.diff","patch_url":"https://github.com/loadimpact/k6/pull/1007.patch","issue_url":"https://api.github.com/repos/loadimpact/k6/issues/1007","number":1007,"state":"open","locked":false,"title":"[WIP] New executors","user":{"login":"na--","id":3336773,"node_id":"MDQ6VXNlcjMzMzY3NzM=","avatar_url":"https://avatars1.githubusercontent.com/u/3336773?v=4","gravatar_id":"","url":"https://api.github.com/users/na--","html_url":"https://github.com/na--","followers_url":"https://api.github.com/users/na--/followers","following_url":"https://api.github.com/users/na--/following{/other_user}","gists_url":"https://api.github.com/users/na--/gists{/gist_id}","starred_url":"https://api.github.com/users/na--/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/na--/subscriptions","organizations_url":"https://api.github.com/users/na--/orgs","repos_url":"https://api.github.com/users/na--/repos","events_url":"https://api.github.com/users/na--/events{/privacy}","received_events_url":"https://api.github.com/users/na--/received_events","type":"User","site_admin":false},"body":"This pull request totally rewrites the old local executor and a bunch of other things. It builds on https://github.com/loadimpact/k6/pull/913 and introduces quite a lot of new functionality, but it also has some minor breaking changes.\r\n\r\n### New features and changes\r\n\r\n#### New executors\r\n\r\nThe biggest change in this PR is the introduction of 7 distinct new VU executors:\r\n- [x] `shared-iterations`, a.k.a. `iterations` + `vus`.\r\n- [x] `constant-looping-vus`, a.k.a. `duration` + `vus`.\r\n- [x] `variable-looping-vus`, a.k.a. `stages` + `vus`.\r\n- [x] `externally-controlled` is similar to `variable-looping-vus`, but the number of initialized and active VUs at any given time can be controlled by the k6 REST API - it's the only executor that could be paused or controlled while it's running (closes https://github.com/loadimpact/k6/issues/867, closes https://github.com/loadimpact/k6/issues/1028).\r\n- [x] `per-vu-iterations` is а new feature that allows each configured VU to execute an exact number of iterations; the shared iterations have caused confusion before and there are legitimate reasons people want an equal number of iterations for each VU (https://github.com/loadimpact/k6/issues/663, https://github.com/loadimpact/k6/issues/627, https://github.com/loadimpact/k6/issues/378, https://github.com/loadimpact/k6/issues/381 and probably others).\r\n- [x] `constant-arrival-rate` executes a constant number of iterations per second (closes https://github.com/loadimpact/k6/issues/550).\r\n- [x] `variable-arrival-rate` executes a variable number of iterations per second, specified as ramp-ups or ramp-downs `stages`, similar to how the `variable-looping-vus` is configured.\r\n\r\nThese executors can be configured via the new `execution` JS/JSON option. For now, they aren't directly configurable via CLI flags or environment variables.\r\n\r\nHowever, most of the old simple k6 uses where `stages`, or `iterations` or `duration` are specified in any way, including via CLI flags and env vars, are still supported. They are just transparently converted to their respective new `execution` executor configurations. There are some breaking changes here, described in detail in the *Breaking Changes* section below, but generally only when there is a conflict or ambiguity in the specified configuration.\r\n\r\n#### Other new features\r\n\r\n- [x] Multiple different executors can be configured in a single test run, both sequentially and in parallel (mostly closes https://github.com/loadimpact/k6/issues/239).\r\n- [x] Each executor has a `startTime` property, which defines at what time relative to the test run start it will start executing.\r\n- [x] VUs are reused between the different configured executors when that's possible.\r\n- [x] Executors have new `gracefulStop` property that allows for iterations to complete gracefully for some amount of time after the normal executor duration is over (closes https://github.com/loadimpact/k6/issues/879); even with `gracefulStop=0`, i.e. the old behavior, metrics are emitted and processed in a much saner way (closes https://github.com/loadimpact/k6/issues/1033)\r\n- [x] Validation of the supplied execution configuration is very strict (closes https://github.com/loadimpact/k6/issues/875 and slightly helps with https://github.com/loadimpact/k6/issues/883)\r\n- [x] There is a new feature called execution segments that allows tests to be easily partitioned between multiple k6 instances (implements the execution parts of https://github.com/loadimpact/k6/issues/997 and helps towards https://github.com/loadimpact/k6/issues/140)\r\n- [x] There are separate descriptions and real-time thread-safe progress bars for each individual executor.\r\n- [ ] Different executors can execute different functions than the `default` exported one.\r\n- [ ] Different executors can have different environment variables.\r\n\r\n### Example of the new config\r\n\r\n```js\r\nimport { sleep } from \"k6\";\r\n\r\nexport let options = {\r\n  execution: {\r\n    stages_up_down: {\r\n      type: \"variable-looping-vus\",\r\n      startVUs: 0,\r\n      stages: [\r\n        { duration: \"10s\", target: 20 },\r\n        { duration: \"10s\", target: 0 },\r\n      ],\r\n      gracefulRampDown: \"0s\",\r\n      gracefulStop: \"0s\",\r\n    },\r\n    stages_down_up: {\r\n      type: \"variable-looping-vus\",\r\n      startVUs: 20,\r\n      stages: [\r\n        { duration: \"10s\", target: 0 },\r\n        { duration: \"10s\", target: 20 },\r\n      ],\r\n      gracefulRampDown: \"0s\",\r\n      gracefulStop: \"0s\",\r\n    },\r\n    const_loop_vus: {\r\n      type: \"constant-looping-vus\",\r\n      vus: 20,\r\n      duration: \"20s\",\r\n      gracefulStop: \"0s\",\r\n    },\r\n    constant_arr_rate: {\r\n      type: \"constant-arrival-rate\",\r\n      rate: 20,\r\n      timeUnit: \"1s\",\r\n      duration: \"10s\",\r\n      preAllocatedVUs: 10,\r\n      maxVUs: 20,\r\n      startTime: \"20s\",\r\n      gracefulStop: \"0s\",\r\n    },\r\n    variable_arr_rate: {\r\n      type: \"variable-arrival-rate\",\r\n      startRate: 20,\r\n      timeUnit: \"1s\",\r\n      preAllocatedVUs: 10,\r\n      maxVUs: 20,\r\n      startTime: \"20s\",\r\n      stages: [\r\n        { target: 0, duration: \"5s\" },\r\n        { target: 20, duration: \"5s\" },\r\n      ],\r\n      gracefulStop: \"0s\",\r\n    },\r\n    per_vu_iters: {\r\n      type: \"per-vu-iterations\",\r\n      vus: 20,\r\n      iterations: 10,\r\n      startTime: \"30s\",\r\n      maxDuration: \"10s\",\r\n      gracefulStop: \"10s\",\r\n    },\r\n    shared_iters: {\r\n      type: \"shared-iterations\",\r\n      vus: 20,\r\n      iterations: 200,\r\n      startTime: \"30s\",\r\n      maxDuration: \"10s\",\r\n      gracefulStop: \"10s\",\r\n    },\r\n    adjustable_at_will: {\r\n      type: \"externally-controlled\",\r\n      vus: 5,\r\n      maxVUs: 10,\r\n      duration: \"40s\",\r\n    },\r\n  },\r\n};\r\n\r\nexport default function () {\r\n  console.log(`Start VU ${__VU} ITER ${__ITER}`);\r\n  sleep(0.5 + Math.random() * 0.5);\r\n  console.log(`Done VU ${__VU} ITER ${__ITER}`);\r\n}\r\n```\r\n\r\n### Breaking changes\r\n\r\nThere are a few breaking changes caused by this PR:\r\n- Execution config options (`execution`, `stages`, `iterations`, `duration`) from \"upper\" config layers overwrite execution options from \"lower\" (i.e. CLI flags > environment variables > JS options > JSON options) config layers. For example, the `--iterations` CLI flag will overwrite any execution options set as environment variables (e.g. `K6_DURATION`, `K6_STAGES`, etc.) or script options (`stages: [ /* ... */]`, `execution: { /* ... */ }`, etc. ).\r\n- Using different execution config options on the same level is now a configuration conflict error and will abort the script. For example, executing `k6 run --duration 10s --stages 5s:20 script.js` won't work (closes https://github.com/loadimpact/k6/issues/812). The only exception is combining `duration` and `iterations`, which will result in a `shared-iterations` executor with the specified non-default `maxDuration` (https://github.com/loadimpact/k6/issues/1058).\r\n- The k6 REST API for controlling script execution (i.e. the `k6 pause`, `k6 scale` commands) now only works when a `externally-controlled` executor is configured in the `execution` config. The initial pausing of a test (i.e. `k6 run --paused script.js`) still works with all executor types, but once the test is started with `k6 resume` (or the corresponding REST API call), it can't be paused again unless only the `externally-controlled` executor is used.\r\n- Previously, running a script with `k6 run --paused script.js` would have still executed the script's `setup()` function (if it was present and wasn't explicitly disabled with `--no-setup`) and paused immediately after. Now, k6 will pause before it executes `setup()`.\r\n- The `vusMax` / `K6_VUS_MAX` / ` -m` / `--max` option is deprecated - it was previously used for the control of the initialized VUs by the REST API. Since that has now been restricted to the `externally-controlled` executor, the equivalent option there is called `maxVUs`.\r\n- Tests with infinite duration are now only possible via the `externally-controlled` executor.\r\n- Previously, all iterations were interruptible - as soon as the specified `duration` expired, or when VUs were ramped down in a stage, any running iterations were interrupted. Now all executors besides the `externally-controlled` one have a `gracefulStop` period of `30s` by default (closes https://github.com/loadimpact/k6/issues/898). Additionally, `variable-looping-vus` executor has a `gracefulRampDown` parameter that configures the ramp-down grace period. For those periods, no new iterations will be started by the executors, but any currently running iterations will be allowed up to the specified periods to finish their execution.\r\n\r\n### Broken things and TODOs that remain be fixed in this PR:\r\n- [x] updating the `externally-controlled` executor's parameters via the REST API\r\n- [x] update the description of this pull request :smile:\r\n- [x] forward-port the fixes in https://github.com/loadimpact/k6/pull/1057 and https://github.com/loadimpact/k6/pull/1076\r\n- [x] rename things according to https://github.com/loadimpact/k6/pull/1007#issuecomment-497319205\r\n- [ ] support for cloud execution\r\n- [ ] the usage report\r\n- [ ] writing a lot more tests... this PR should hopefully significantly increase the code coverage of k6\r\n- [ ] improving the multi-progressbar alignments and sizing\r\n- [ ] fix the `arrival-rate` distribution bugs, especially when there are execution segments: https://github.com/loadimpact/k6/pull/1007#issuecomment-522883821\r\n- [ ] fix a bug where Ctrl+C doesn't work while the `k6 scale` command to the `externally-controlled` executor is running\r\n- [ ] remove the `ERRO context cancelled` message error message that's sometimes shown when an iteration is interrupted\r\n- [ ] (evaluation needed) fix that `k6 inspect` doesn't fail when there are validation errors in options\r\n- [ ] update the release notes and the `README`\r\n- [ ] update the [k6 architecture wiki page](https://github.com/loadimpact/k6/wiki/Architecture)\r\n- [ ] whatever @MStoykov says :smile:\r\n\r\n### `TODO`s in the code that will be handled in future pull requests, i.e. for now only issues will be created:\r\n- [ ] handle Ctrl+C graceful shutdown + teardown execution\r\n- [ ] have a special error code for Ctrl+C interrupts\r\n- [x] ~tag metrics from different executors differently~ (already described in https://github.com/loadimpact/k6/issues/796)\r\n- [ ] JavaScript helper functions that could be used to build this new complicated `execution` configuration, but with a better user experience than manually writing it as a JSON\r\n- [ ] changes and additions to the metrics and tags k6 emits, given the new executors - this includes tagging metrics with the executor ID by default, maybe split the vus metric by executor, a new metric for insufficient VUs by the arrival-rate executors\r\n\r\nThings that need to be done shortly before or after this PR is merged in `master`:\r\n- [ ] a lot of manual testing, especially on different OSes\r\n- [ ] update the documentation (https://github.com/loadimpact/k6/issues/551)\r\n","created_at":"2019-04-23T15:05:10Z","updated_at":"2019-10-10T08:57:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0e7f1f36e38a5d43083ae31b53a6c7adb81f6843","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":{"url":"https://api.github.com/repos/loadimpact/k6/milestones/4","html_url":"https://github.com/loadimpact/k6/milestone/4","labels_url":"https://api.github.com/repos/loadimpact/k6/milestones/4/labels","id":3330403,"node_id":"MDk6TWlsZXN0b25lMzMzMDQwMw==","number":4,"title":"v1.0.0","description":"","creator":{"login":"robingustafsson","id":1792533,"node_id":"MDQ6VXNlcjE3OTI1MzM=","avatar_url":"https://avatars1.githubusercontent.com/u/1792533?v=4","gravatar_id":"","url":"https://api.github.com/users/robingustafsson","html_url":"https://github.com/robingustafsson","followers_url":"https://api.github.com/users/robingustafsson/followers","following_url":"https://api.github.com/users/robingustafsson/following{/other_user}","gists_url":"https://api.github.com/users/robingustafsson/gists{/gist_id}","starred_url":"https://api.github.com/users/robingustafsson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robingustafsson/subscriptions","organizations_url":"https://api.github.com/users/robingustafsson/orgs","repos_url":"https://api.github.com/users/robingustafsson/repos","events_url":"https://api.github.com/users/robingustafsson/events{/privacy}","received_events_url":"https://api.github.com/users/robingustafsson/received_events","type":"User","site_admin":false},"open_issues":30,"closed_issues":45,"state":"open","created_at":"2018-05-08T15:37:36Z","updated_at":"2019-09-25T12:46:07Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/loadimpact/k6/pulls/1007/commits","review_comments_url":"https://api.github.com/repos/loadimpact/k6/pulls/1007/comments","review_comment_url":"https://api.github.com/repos/loadimpact/k6/pulls/comments{/number}","comments_url":"https://api.github.com/repos/loadimpact/k6/issues/1007/comments","statuses_url":"https://api.github.com/repos/loadimpact/k6/statuses/5700ea66849ff84904bd22df8cba140935761de6","head":{"label":"loadimpact:new-schedulers","ref":"new-schedulers","sha":"5700ea66849ff84904bd22df8cba140935761de6","user":{"login":"loadimpact","id":2271486,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyNzE0ODY=","avatar_url":"https://avatars2.githubusercontent.com/u/2271486?v=4","gravatar_id":"","url":"https://api.github.com/users/loadimpact","html_url":"https://github.com/loadimpact","followers_url":"https://api.github.com/users/loadimpact/followers","following_url":"https://api.github.com/users/loadimpact/following{/other_user}","gists_url":"https://api.github.com/users/loadimpact/gists{/gist_id}","starred_url":"https://api.github.com/users/loadimpact/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loadimpact/subscriptions","organizations_url":"https://api.github.com/users/loadimpact/orgs","repos_url":"https://api.github.com/users/loadimpact/repos","events_url":"https://api.github.com/users/loadimpact/events{/privacy}","received_events_url":"https://api.github.com/users/loadimpact/received_events","type":"Organization","site_admin":false},"repo":{"id":54400687,"node_id":"MDEwOlJlcG9zaXRvcnk1NDQwMDY4Nw==","name":"k6","full_name":"loadimpact/k6","private":false,"owner":{"login":"loadimpact","id":2271486,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyNzE0ODY=","avatar_url":"https://avatars2.githubusercontent.com/u/2271486?v=4","gravatar_id":"","url":"https://api.github.com/users/loadimpact","html_url":"https://github.com/loadimpact","followers_url":"https://api.github.com/users/loadimpact/followers","following_url":"https://api.github.com/users/loadimpact/following{/other_user}","gists_url":"https://api.github.com/users/loadimpact/gists{/gist_id}","starred_url":"https://api.github.com/users/loadimpact/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loadimpact/subscriptions","organizations_url":"https://api.github.com/users/loadimpact/orgs","repos_url":"https://api.github.com/users/loadimpact/repos","events_url":"https://api.github.com/users/loadimpact/events{/privacy}","received_events_url":"https://api.github.com/users/loadimpact/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/loadimpact/k6","description":"A modern load testing tool, using Go and JavaScript - https://k6.io","fork":false,"url":"https://api.github.com/repos/loadimpact/k6","forks_url":"https://api.github.com/repos/loadimpact/k6/forks","keys_url":"https://api.github.com/repos/loadimpact/k6/keys{/key_id}","collaborators_url":"https://api.github.com/repos/loadimpact/k6/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/loadimpact/k6/teams","hooks_url":"https://api.github.com/repos/loadimpact/k6/hooks","issue_events_url":"https://api.github.com/repos/loadimpact/k6/issues/events{/number}","events_url":"https://api.github.com/repos/loadimpact/k6/events","assignees_url":"https://api.github.com/repos/loadimpact/k6/assignees{/user}","branches_url":"https://api.github.com/repos/loadimpact/k6/branches{/branch}","tags_url":"https://api.github.com/repos/loadimpact/k6/tags","blobs_url":"https://api.github.com/repos/loadimpact/k6/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/loadimpact/k6/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/loadimpact/k6/git/refs{/sha}","trees_url":"https://api.github.com/repos/loadimpact/k6/git/trees{/sha}","statuses_url":"https://api.github.com/repos/loadimpact/k6/statuses/{sha}","languages_url":"https://api.github.com/repos/loadimpact/k6/languages","stargazers_url":"https://api.github.com/repos/loadimpact/k6/stargazers","contributors_url":"https://api.github.com/repos/loadimpact/k6/contributors","subscribers_url":"https://api.github.com/repos/loadimpact/k6/subscribers","subscription_url":"https://api.github.com/repos/loadimpact/k6/subscription","commits_url":"https://api.github.com/repos/loadimpact/k6/commits{/sha}","git_commits_url":"https://api.github.com/repos/loadimpact/k6/git/commits{/sha}","comments_url":"https://api.github.com/repos/loadimpact/k6/comments{/number}","issue_comment_url":"https://api.github.com/repos/loadimpact/k6/issues/comments{/number}","contents_url":"https://api.github.com/repos/loadimpact/k6/contents/{+path}","compare_url":"https://api.github.com/repos/loadimpact/k6/compare/{base}...{head}","merges_url":"https://api.github.com/repos/loadimpact/k6/merges","archive_url":"https://api.github.com/repos/loadimpact/k6/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/loadimpact/k6/downloads","issues_url":"https://api.github.com/repos/loadimpact/k6/issues{/number}","pulls_url":"https://api.github.com/repos/loadimpact/k6/pulls{/number}","milestones_url":"https://api.github.com/repos/loadimpact/k6/milestones{/number}","notifications_url":"https://api.github.com/repos/loadimpact/k6/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/loadimpact/k6/labels{/name}","releases_url":"https://api.github.com/repos/loadimpact/k6/releases{/id}","deployments_url":"https://api.github.com/repos/loadimpact/k6/deployments","created_at":"2016-03-21T15:30:24Z","updated_at":"2019-10-09T20:17:30Z","pushed_at":"2019-10-10T08:05:59Z","git_url":"git://github.com/loadimpact/k6.git","ssh_url":"git@github.com:loadimpact/k6.git","clone_url":"https://github.com/loadimpact/k6.git","svn_url":"https://github.com/loadimpact/k6","homepage":"","size":11614,"stargazers_count":5507,"watchers_count":5507,"language":"Go","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":282,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":266,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":282,"open_issues":266,"watchers":5507,"default_branch":"master"}},"base":{"label":"loadimpact:master","ref":"master","sha":"a2077dd22a86662ef3cd699bc57b0048136e51ba","user":{"login":"loadimpact","id":2271486,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyNzE0ODY=","avatar_url":"https://avatars2.githubusercontent.com/u/2271486?v=4","gravatar_id":"","url":"https://api.github.com/users/loadimpact","html_url":"https://github.com/loadimpact","followers_url":"https://api.github.com/users/loadimpact/followers","following_url":"https://api.github.com/users/loadimpact/following{/other_user}","gists_url":"https://api.github.com/users/loadimpact/gists{/gist_id}","starred_url":"https://api.github.com/users/loadimpact/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loadimpact/subscriptions","organizations_url":"https://api.github.com/users/loadimpact/orgs","repos_url":"https://api.github.com/users/loadimpact/repos","events_url":"https://api.github.com/users/loadimpact/events{/privacy}","received_events_url":"https://api.github.com/users/loadimpact/received_events","type":"Organization","site_admin":false},"repo":{"id":54400687,"node_id":"MDEwOlJlcG9zaXRvcnk1NDQwMDY4Nw==","name":"k6","full_name":"loadimpact/k6","private":false,"owner":{"login":"loadimpact","id":2271486,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyNzE0ODY=","avatar_url":"https://avatars2.githubusercontent.com/u/2271486?v=4","gravatar_id":"","url":"https://api.github.com/users/loadimpact","html_url":"https://github.com/loadimpact","followers_url":"https://api.github.com/users/loadimpact/followers","following_url":"https://api.github.com/users/loadimpact/following{/other_user}","gists_url":"https://api.github.com/users/loadimpact/gists{/gist_id}","starred_url":"https://api.github.com/users/loadimpact/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loadimpact/subscriptions","organizations_url":"https://api.github.com/users/loadimpact/orgs","repos_url":"https://api.github.com/users/loadimpact/repos","events_url":"https://api.github.com/users/loadimpact/events{/privacy}","received_events_url":"https://api.github.com/users/loadimpact/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/loadimpact/k6","description":"A modern load testing tool, using Go and JavaScript - https://k6.io","fork":false,"url":"https://api.github.com/repos/loadimpact/k6","forks_url":"https://api.github.com/repos/loadimpact/k6/forks","keys_url":"https://api.github.com/repos/loadimpact/k6/keys{/key_id}","collaborators_url":"https://api.github.com/repos/loadimpact/k6/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/loadimpact/k6/teams","hooks_url":"https://api.github.com/repos/loadimpact/k6/hooks","issue_events_url":"https://api.github.com/repos/loadimpact/k6/issues/events{/number}","events_url":"https://api.github.com/repos/loadimpact/k6/events","assignees_url":"https://api.github.com/repos/loadimpact/k6/assignees{/user}","branches_url":"https://api.github.com/repos/loadimpact/k6/branches{/branch}","tags_url":"https://api.github.com/repos/loadimpact/k6/tags","blobs_url":"https://api.github.com/repos/loadimpact/k6/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/loadimpact/k6/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/loadimpact/k6/git/refs{/sha}","trees_url":"https://api.github.com/repos/loadimpact/k6/git/trees{/sha}","statuses_url":"https://api.github.com/repos/loadimpact/k6/statuses/{sha}","languages_url":"https://api.github.com/repos/loadimpact/k6/languages","stargazers_url":"https://api.github.com/repos/loadimpact/k6/stargazers","contributors_url":"https://api.github.com/repos/loadimpact/k6/contributors","subscribers_url":"https://api.github.com/repos/loadimpact/k6/subscribers","subscription_url":"https://api.github.com/repos/loadimpact/k6/subscription","commits_url":"https://api.github.com/repos/loadimpact/k6/commits{/sha}","git_commits_url":"https://api.github.com/repos/loadimpact/k6/git/commits{/sha}","comments_url":"https://api.github.com/repos/loadimpact/k6/comments{/number}","issue_comment_url":"https://api.github.com/repos/loadimpact/k6/issues/comments{/number}","contents_url":"https://api.github.com/repos/loadimpact/k6/contents/{+path}","compare_url":"https://api.github.com/repos/loadimpact/k6/compare/{base}...{head}","merges_url":"https://api.github.com/repos/loadimpact/k6/merges","archive_url":"https://api.github.com/repos/loadimpact/k6/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/loadimpact/k6/downloads","issues_url":"https://api.github.com/repos/loadimpact/k6/issues{/number}","pulls_url":"https://api.github.com/repos/loadimpact/k6/pulls{/number}","milestones_url":"https://api.github.com/repos/loadimpact/k6/milestones{/number}","notifications_url":"https://api.github.com/repos/loadimpact/k6/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/loadimpact/k6/labels{/name}","releases_url":"https://api.github.com/repos/loadimpact/k6/releases{/id}","deployments_url":"https://api.github.com/repos/loadimpact/k6/deployments","created_at":"2016-03-21T15:30:24Z","updated_at":"2019-10-09T20:17:30Z","pushed_at":"2019-10-10T08:05:59Z","git_url":"git://github.com/loadimpact/k6.git","ssh_url":"git@github.com:loadimpact/k6.git","clone_url":"https://github.com/loadimpact/k6.git","svn_url":"https://github.com/loadimpact/k6","homepage":"","size":11614,"stargazers_count":5507,"watchers_count":5507,"language":"Go","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":282,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":266,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":282,"open_issues":266,"watchers":5507,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/loadimpact/k6/pulls/1007"},"html":{"href":"https://github.com/loadimpact/k6/pull/1007"},"issue":{"href":"https://api.github.com/repos/loadimpact/k6/issues/1007"},"comments":{"href":"https://api.github.com/repos/loadimpact/k6/issues/1007/comments"},"review_comments":{"href":"https://api.github.com/repos/loadimpact/k6/pulls/1007/comments"},"review_comment":{"href":"https://api.github.com/repos/loadimpact/k6/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/loadimpact/k6/pulls/1007/commits"},"statuses":{"href":"https://api.github.com/repos/loadimpact/k6/statuses/5700ea66849ff84904bd22df8cba140935761de6"}},"author_association":"MEMBER"}}
other: {"actor":{"display_login":"imiric"}}