feat: dedicated reporter command - #125
Conversation
|
Thanks, could you add a short description how the typical actions would change? |
metalwarrior665
left a comment
There was a problem hiding this comment.
Thanks, looks good but let's have broader discussion about how the configs should work.
| .option('report-slack-channel', { type: 'string' }) | ||
| .option('release-slack-channel', { type: 'string' }) | ||
| .option('report-notify-file', { type: 'string', demandOption: true }) | ||
| .option('release-notify-file', { type: 'string', demandOption: true }) |
There was a problem hiding this comment.
I would remove this extra notification and would just always call it "report". If someone wants to do it like we do (maybe we don't anymore) which will be super rare, they would just call notify twice. We could add something like --reportDetail detailed
There was a problem hiding this comment.
This is to create the two separate documents, these two are intended to be use with two separate notify commands, so that the elasticity comes from deciding to notify it or not, but I guess it's correct to make both of them optional, if one wants only the logging on GH.
There was a problem hiding this comment.
I'm arguing about removing release-notify-file completely. Currently, we sort of arbitrarily post one message to #delivary-public-actors (release-slack-channel) and one to #nofit-${repo}(report-slack-channel).
Instead you could have just one notify file and the notify command would decide how to format it to Slack
There was a problem hiding this comment.
Ok, I agree that we should do one file in one file out, it's a question of how the notifier should work with this.
My idea would be that each Notifier must be able to handle a strict union of "type of notification" (as of now: failed-tests, release-public and release-detail) and those can be passed in a single file that will have to be validated and parsed by an helper function before passing it to the notifier which is still chosen by the command flag, not by what is in the config file (however we decide on its structure)
There was a problem hiding this comment.
I haven't really read the internals yet; I'm focusing just on the commands. I think you could just pass any output file (or potentially pipe as we discussed) generated by other commands to the notify command and it would just internally format it based on the target platform and send the notification. If you pass in a different file format, we would just error out.
which is still chosen by the command flag, not by what is in the config file (however we decide on its structure)
As discussed I would try to have 1:1 equivalence in JSON config and CLI flags but it might look too ugly, let's see
| .option('report-file', { type: 'string', demandOption: true }) | ||
| .option('report-slack-channel', { type: 'string' }) | ||
| .option('notify-file', { type: 'string', demandOption: true }) |
There was a problem hiding this comment.
How about unifying this as input-file and output-file for all commands? Then it is more clear which one you need. We could also by default allow piping in and out but some of the outputs are probably too big for that, let;s check
There was a problem hiding this comment.
The unification is a cool idea, we should really try and make it!
As per the piping, I actually did the files because I prefer them, I think they are easier to manage passing them from action to action.
There was a problem hiding this comment.
I would allow at least the input piping since that doesn't dump anything into the console. Basically, the same format as the file. we can think about the std output later
Let's start by mapping each command input (not options) and output
We don't have to do it in this PR, that can be refactored later.
| `report-tests` and `release` don't send notifications themselves — they write a _notify file_ (a JSON payload of `{ "summary": string, "details"?: string[] } | null`, `null` meaning nothing to report) describing what happened. A separate `notify` command then delivers that file through a pluggable notifier (Slack for now), so each command can be composed as its own step in a GitHub Actions workflow: | ||
|
|
||
| ```bash | ||
| npx apify-test-tools report-tests \ |
There was a problem hiding this comment.
Maybe better name
| npx apify-test-tools report-tests \ | |
| npx apify-test-tools create-test-report \ |
| npx apify-test-tools notify \ | ||
| --notify-file test-report.notify.json \ | ||
| --notifier slack \ | ||
| --target "#test-failures" |
There was a problem hiding this comment.
Have you thought about per Actor channels?
There was a problem hiding this comment.
I didn't, but it makes a lot of sense. I think this is something that belongs to the config file!
There was a problem hiding this comment.
Let's just discuss this in the thread below.
| "notifiers": { | ||
| "slack": { "tokenEnvVar": "SLACK_TOKEN" } | ||
| } | ||
| } |
There was a problem hiding this comment.
Let's think this config file deeply through before we start adding stuff.
In high level, ideal structure for me would be that
- All options are available per Actor - but we have to figure out what that means. E.g. for notification, you could have different channels. Then we report only changes related to each Actor to each channel? And if they share a channel, we somehow merge that? I think it is doable we have to think it through.
- The same options are available with actor globs. e.g.
groupConfigs: [{ glob: "clockworks/*", config: { tokenEnvVar: "APIFY_TOKEN_CLOCKWORKS"}]. Direct Actor-level config would have preference (or crash on conflict? or have globs only for configs?). Configs with later (or earlier?) index in theglobalConfigs(naming TBD) array would have preference. I think this will be useful for e-commerce where they will have hundreds of Actors. - And ideally, all the same things are overridable via CLI again with glob configs. I think a neat solution would be to have the same syntax because otherwise it will be very hard to document and understand. E.g. something like
--group-configs "clockworks/*.notifiers.slack.tokenEnvVar"=CLOCKWORKS_SLACK_TOKEN(probably not a valid shell)
There was a problem hiding this comment.
Thinking about it more, I'm leaning towards having 1 and 2 non overlapping, keeping in actors only actorFullName and folder. tokenEnvVar and overrideActorContext can be in configs with globs. I cannot think now of anything that should be elsewhere than globs.
There was a problem hiding this comment.
It might be useful to allow glob on folder, e.g. folderGlob and nameGlob since name is public and you do it for users but folder can be arbitrarily structured E.g. e-commerce has 2 types of Actors with different configs so it would be nice to glob them easily separately.
There was a problem hiding this comment.
What if we allow for groupings? A structure like this
{
"actors": [
{
"tokenEnvVar": "APIFY_TOKEN_TEAM_A",
"notifiers": { "slack": { "target": "#team-a-ci" } },
"actors": [
{ "actorFullName": "team-a/actor-one", "folder": "actors/actor-one" },
{ "actorFullName": "team-a/actor-two", "folder": "actors/actor-two" }
]
},
{
"tokenEnvVar": "APIFY_TOKEN_TEAM_B",
"notifiers": { "slack": { "target": "#some-channel" } },
"actorFullName": "org/standalone-actor",
"folder": "actors/standalone-actor"
}
]
}Will allow us to understand "If actors are in the same grouping they go together when it comes to notification/reporting" unless there is a specific override of the properties in the top level (e.g. a specific channel for the reporting of one specific actor)
There was a problem hiding this comment.
That's also possible, a few cons are
- It would be quite annoying if you have group A use token A, then group B use token B. And then half of group A uses notifier A and other half notifier B. We would then need to illogically chunk it into smaller groups. So in this regard the separate glob based configs are more flexible.
- Would you still want to have the glob override on the CLI command? Since overriding this via command will be quite involving. And if we do globs in the
apify-test-tools.config.jsonwe will use the same parser for it.
There was a problem hiding this comment.
It would be quite annoying if you have group A use token A, then group B use token B. And then half of group A uses notifier A and other half notifier B. We would then need to illogically chunk it into smaller groups. So in this regard the separate glob based configs are more flexible.
I don't think the chunking is needed. With 6 actors it would be like
{
"actors": [
{
"tokenEnvVar": "TOKEN_A",
"notifiers": { "slack": { "target": "#team-a-default" } },
"actors": [
{ "actorFullName": "team-a/actor-1", "notifiers": { "slack": { "target": "#team-a-special" } } },
{ "actorFullName": "team-a/actor-2" },
{ "actorFullName": "team-a/actor-3" }
]
},
{
"tokenEnvVar": "TOKEN_B",
"notifiers": { "slack": { "target": "#team-b-default" } },
"actors": [
{ "actorFullName": "team-b/actor-4" },
{ "actorFullName": "team-b/actor-5", "notifiers": { "slack": { "target": "#team-b-special" } } },
{ "actorFullName": "team-b/actor-6" }
]
}
]
}There was a problem hiding this comment.
even if it might make shit easier for e-commerce.
It is not just e-commerce; we want to offer this for the community, and they also might have large monorepos.
Maybe some root notifier and per-actor override? (yeah it might be too much with 100+ actors tho).
I think the per Actor overrides also can get quite hidden in the large list.
With globbing you have to check each pattern, also what would happen if 2+ patterns match an entry?
Probably later glob trumps earlier, not very clean ofc. But I don't expect some super complex combos, it would be maybe 5 configs per repo.
Extra: maybe a per-actor disable of notify is nice for e-commerce, since they dont really care that much about clanker-made actors.
We should add --actors and --ignore generically to all commands
There was a problem hiding this comment.
I don't think the chunking is needed. With 6 actors it would be like
That looks pretty good. How (if) would you override it through CLI? E.g. with the release double notification
There was a problem hiding this comment.
If we keep the idea from this, channel release channels would also belong in the config and for the CLI I wouldn't do any support other than a flag (that can stay --target) overriding all the channels to the same one, just for local development
There was a problem hiding this comment.
can we meet about this?
lets go nuts on the notion pitching shit
I have this feeling we could benefit of thinking about this in a deeper level, not just tweaking the config for this new feature, and then again for the next one, etc.
Patai5
left a comment
There was a problem hiding this comment.
I'm not sure how much this is needed. IMO this is not a big deal at least for us, and I doubt that it will be fore some community developer either.
If they need some release notes, then they can probably do so better in their own CI 🤷
Otherwise for you to consider: personally for a top level design of the code, it would be really nice to have a class interface for the Notifier class rather than a raw function. It would be nice for extendability for community developers. And for the assrtions for the configurations (e.g. the slack token assertion) could be done directly in the class constructor, rather than only on runtime of the function.
Thanks!
| ) | ||
| .command( | ||
| 'report-tests', | ||
| 'create-test-report', |
There was a problem hiding this comment.
How about we pass the vitest report to notify directly and parse it there? What would be the advantage of this middleman command?
Closes #119
Adds a
notifycommand that delivers test and release notifications through a pluggable notifier (Slack for now), decoupled from the commands that produce them.create-test-reportandreleasedon't send notifications or build any message text themselves — they each write a typedNotifyDocumentdescribing what happened, always to stdout (or stderr on--dry-run, so it stays inspectable), and optionally to a file via--output. TODO These two commands will probably be reworked but this was the easiest way to make the diff on this PR at a minimum.notifyreads that document — from--inputor piped in on stdin — and hands it to the chosen notifier'sformat()method, which turns the structured data into that notifier's message and decides whether there's anything worth sending at all (e.g. a test-report with zero failures sends nothing). Each notifier is a class (assertConfig/format/send), so adding a new one is a matter of implementing that interface, not branching insidenotify. Each new notifier would be responsible to create their own formatting for each document type.notify --view <dev|public>picks which prose to render, so callers runnotifytwice (once per view) against the one documentreleaseproduced.id(built from the actor and the full test name) so the same failure can be recognized across separate runs, e.g. for tracking flaky tests over time.apify-test-tools.config.json, undernotifiers.<name>. Every notifier has atargetsmap — one entry per document type it can send (release-report entries are further keyed by view) — and only needs the specific entry it's actually asked to use;notifyfails with a clear error if that one is missing. Notifier-specific credentials (Slack'stokenEnvVar) live alongside it. There's no CLI flag to override a target or a credential.BREAKING!:
Callers need
apify-test-tools.config.jsonto include atargetsmap for each notifier they use, and to invoke the CLI with its current flags:create-test-report --input <file> [--output <file>],release --output <file>,notify [--input <file>] --notifier <name> [--view dev|public]. This includes updating thegithub-actions-sourceworkflows, which still use the old flag names.