From 494354c57be3b2d823a356d7f74105b47ef3c441 Mon Sep 17 00:00:00 2001 From: Ashish Padhy <100484401+Shurtu-gal@users.noreply.github.com> Date: Wed, 8 May 2024 19:08:29 +0530 Subject: [PATCH] feat: initial infra for slack intergration (#1131) Co-authored-by: Sergio Moya <1083296+smoya@users.noreply.github.com>%0ACo-authored-by: Quetzalli %0ACo-authored-by: asyncapi-bot --- .github/workflows/slack-integration.yml | 45 + .github/workflows/slack/.terraform.lock.hcl | 25 + .github/workflows/slack/README.md | 147 +++ .github/workflows/slack/channels/channels.tf | 85 ++ .../workflows/slack/channels/channels.yaml | 255 +++++ .github/workflows/slack/groups/groups.tf | 74 ++ .github/workflows/slack/groups/groups.yaml | 53 + .github/workflows/slack/slack.tf | 36 + .github/workflows/slack/terraform.tfstate | 999 ++++++++++++++++++ .github/workflows/slack/users/users.tf | 30 + .gitignore | 5 +- TSC_MEMBERSHIP.md | 9 + WORKING_GROUPS.md | 11 + WORKING_GROUPS.yaml | 8 +- 14 files changed, 1777 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/slack-integration.yml create mode 100644 .github/workflows/slack/.terraform.lock.hcl create mode 100644 .github/workflows/slack/README.md create mode 100644 .github/workflows/slack/channels/channels.tf create mode 100644 .github/workflows/slack/channels/channels.yaml create mode 100644 .github/workflows/slack/groups/groups.tf create mode 100644 .github/workflows/slack/groups/groups.yaml create mode 100644 .github/workflows/slack/slack.tf create mode 100644 .github/workflows/slack/terraform.tfstate create mode 100644 .github/workflows/slack/users/users.tf diff --git a/.github/workflows/slack-integration.yml b/.github/workflows/slack-integration.yml new file mode 100644 index 000000000..734fe0f9b --- /dev/null +++ b/.github/workflows/slack-integration.yml @@ -0,0 +1,45 @@ +name: Automatic Slack Management + +on: + push: + paths: + - '**/slack/**/*' + - 'MAINTAINERS.yaml' + - 'WORKING_GROUPS.yaml' + +jobs: + deploy-changes-to-slack: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Deploy changes to Slack + run: | + cd .github/workflows/slack + terraform init + terraform apply \ + -var "slack_token=${{ secrets.SLACK_TOKEN }}" \ + -auto-approve + - name: Check if there are any uncommitted changes + id: git-check + run: | + # Set the output should_push to true if there are uncommitted changes + if [ -n "$(git status --porcelain)" ]; then + echo "Changes detected" + echo "should_push=true" >> $GITHUB_OUTPUT + else + echo "No changes detected" + echo "should_push=false" >> $GITHUB_OUTPUT + fi + - name: Push changes to GitHub + if: steps.git-check.outputs.should_push == 'true' + uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # use 4.2.4 https://github.com/peter-evans/create-pull-request/releases/tag/v4.2.4 + with: + token: ${{ secrets.GH_TOKEN }} + commit-message: 'chore(slack): update slack configuration' + committer: asyncapi-bot + author: asyncapi-bot + title: 'ci(slack): update slack configuration' + body: 'This PR was automatically created by the Automatic Slack Management GitHub Action.' + branch: 'chore/slack-update-${{ github.run_number }}' + base: 'main' \ No newline at end of file diff --git a/.github/workflows/slack/.terraform.lock.hcl b/.github/workflows/slack/.terraform.lock.hcl new file mode 100644 index 000000000..483c5f8a7 --- /dev/null +++ b/.github/workflows/slack/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/pablovarela/slack" { + version = "1.2.2" + constraints = "~> 1.0" + hashes = [ + "h1:0cQTyJPZUA2AYz+tKQ4z6Vbm0LwZbvtLOAsStWxFkIE=", + "h1:eNX77+dnJ7JRx9xX7WHMNy4QUxlcEXDUzldOunLDRNk=", + "zh:001870e887a1e29a328b87f6431444d8d60e3c7e958fae2e885fbfc4d345886a", + "zh:065ff64914739cb2942a5a133b2f6e37c3a4278199ca2416d4c578f4d5a12659", + "zh:383d283b2344732b1c2514c072f4d93de2fd0660d478381756f35ca1be69da41", + "zh:38a393a7c294e81f4e951a1bde494e79868144f82cdb9662e6d4e0428571bf54", + "zh:51c81d69806acb4048aef69dc2fa3e2464b4c86c68009e4de93814c42783e736", + "zh:5ad19e4173069c503a7fdc55fc84de2358d021536039e72efffd79f95dc4245e", + "zh:63b39c1d32a5cb0ce2afee114d43b1444653cc78b45d252e2c0031fbb0b0ffbf", + "zh:701a19598b3e554b08d203507c215b218aa21646ea70dd2e8f20e232cb1c138e", + "zh:77f854eec925a895f68ab8b744728fe6203f6a1771ef27200cfce67b6836f168", + "zh:8b7cd7311034eb35f0d4e1473048798aa826db2194ae159596846eda9b96c562", + "zh:ac3a062bd1502a2e9059a14e68b02f09cebcff8bda25a9b9dc5382919eddbf58", + "zh:b1f4f5fd6d88ca34f8d996898759213c9acf5498058c269d98ab0d1b7e91ce2d", + "zh:efb2befca31fe7a0682513077fcb43d3d50170661fb5b26b1920ee4f8fd9c6a6", + "zh:fdd9b048446fbc05363b75b607986be803ea36179a61d8151497a5c0f24d5630", + ] +} diff --git a/.github/workflows/slack/README.md b/.github/workflows/slack/README.md new file mode 100644 index 000000000..44625aa90 --- /dev/null +++ b/.github/workflows/slack/README.md @@ -0,0 +1,147 @@ +## Infrastructure for slack integration + +This directory contains the infrastructure for Slack integration. It is used to create/manage Slack channels and groups and invite users to Slack channels. The Slack integration is implemented using the [slack-terraform-provider](https://github.com/pablovarela/terraform-provider-slack). + +### Prerequisites + +- [A slack App](https://api.slack.com/apps) with the following scopes under `User Token Scopes` in `OAuth & Permissions`: + + Write Permissions: + - `channels:write` + - `groups:write` + - `usergroups:write` + + Read Permissions: + - `channels:read` + - `groups:read` + - `usergroups:read` + +> [!CAUTION] +> Try to use a bot to log into Slack to prevent any changes from being attributed to the workspace owner. This is due to using a `user token` for authentication, which does the changes on behalf of the user who created the token. + +- [API Token](https://api.slack.com/apps) after installing the app in your workspace. ( `xoxp-` ) + +- [Terraform](https://www.terraform.io/downloads.html) installed on your local machine. + +### Usage + +- Create a `terraform.tfvars` file in the `slack` directory with the following content: + +```hcl +slack_token = "xoxp-" +``` + +- Run the following commands to create the Slack resources: + +```bash +terraform init +terraform apply +``` + +> [!TIP] +> The `terraform apply` command will create the resources better to use `terraform plan` to see the changes before applying. + +### How it works + +Three main resources are created using the slack integration: + +- `slack_channel`: This resource creates a slack channel. The channels are defined in the [channels.yaml](./channels/channels.yaml) file. with the structure explained there. + +- `slack_usergroup`: This resource creates a Slack user group. The usergroups are defined in the [usergroups.yaml](./groups/groups.yaml) file, and their structure is explained there. + +> [!CAUTION] +> The user groups should be unique across the workspace (i.e., no channel, user, or user group should have the same handle). Also, in case of user groups mentioned in the yaml existing in the workspace, you have to run the following command to import it to terraform state: +> ```bash +> terraform import module.groups.slack_usergroup.[\"\"] +> +> # Example +> terraform import module.groups.slack_usergroup.wg_groups[\"Developer Experience\"] +> ``` + +- `slack_user`: This resource invites users to the Slack workspace. The users are defined in the [users.tf](./users/users.tf) file, and their structure is explained there. + +### Pitfalls + +- Use of bot token of the format `xoxo-` is not supported for creating user groups. +- The user group should be unique across the workspace (i.e., no channel, user, or user group should have the same handle). +- Please [import](#importing-existing-resources) the user groups to terraform state if they already exist in the workspace, as they **cannot be deleted** in Slack 😢. + +> [!IMPORTANT] +> The terraform state will overwrite any description, name, or topic change. It is better to manage the changes in the YAML files and then apply them. However, the terraform state will not affect bookmarks, pinned items, etc. + +### Importing existing resources + +In case you have existing resources such as channels, user groups in the workspace, you can import them to the terraform state by transforming the `json` response from the slack API. An example script can be seen below: + +```javascript +const fs = require('fs'); +const fetch = require('node-fetch'); + +const token = 'xoxp-'; + +const fetchResource = async (resource, url_params) => { + // convert the url_params to query string + const url = new URL(`https://slack.com/api/${resource}`); + Object.keys(url_params).forEach(key => url.searchParams.append(key, url_params[key])); + const response = await fetch(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': `Bearer ${token}` + } + }); + const data = await response.json(); + return data; +} + +async function main() { + const channels = await fetchResource('conversations.list', { exclude_archived: true }); + const usergroups = await fetchResource('usergroups.list', { include_users: true }); + + channels.channels.forEach(channel => { + console.log(`terraform import module.channels.slack_conversation.channels[\\"${channel.name}\\"] ${channel.id}`); + }); + + usergroups.usergroups.forEach(usergroup => { + console.log(`terraform import module.groups.slack_usergroup.wg_groups[\\"${usergroup.name}\\"] ${usergroup.id}`); + }); +} + + +main(); +``` + +### What all can be done? + +#### Groups + +The groups can be mentioned in the slack messages using the `@` syntax. Addition of groups can be done by adding the group to the [groups.yaml](./groups/groups.yaml) file. + +The following groups are being created currently: +- `tsc` + + This group is for the Technical Steering Committee members mentioned in the [TSC_MEMBERS](../../../TSC_MEMBERS.json) file. Can be used to mention all the TSC members at once. + +- `maintainers` + + This group is for the all maintainers of the repository mentioned in the [MAINTAINERS](../../../MAINTAINERS.yaml) file. Can be used to mention all the maintainers at once. + +- `studio` + + This group consists of members actively working on the studio project. + +- `coc_commitee` + + This group consists of members of the Code of Conduct committee. + +In addition to these groups are also being created for each working group mentioned in the [WORKING_GROUPS](../../../WORKING_GROUPS.yaml) file. Example: `@dx_wg`. + +We are also having groups for maintainers of each repository mentioned in the [MAINTAINERS](../../../MAINTAINERS.yaml) file. You can mention the maintainers of a repository using `@maintainers_`. Example: `@maintainers_studio`. + +#### Channels + +Two types of channels are being created currently: + +- General channels: The channels are defined in the [channels.yaml](./channels/channels.yaml) file with the structure explained there. + +- Working group channels: The working group channels are created for each working group mentioned in the [WORKING_GROUPS](../../../WORKING_GROUPS.yaml) file. The channels are created with the name `wg_` or custom nameas configured in the [WORKING_GROUPS](../../../WORKING_GROUPS.yaml) file. diff --git a/.github/workflows/slack/channels/channels.tf b/.github/workflows/slack/channels/channels.tf new file mode 100644 index 000000000..2f6f9d9ae --- /dev/null +++ b/.github/workflows/slack/channels/channels.tf @@ -0,0 +1,85 @@ +terraform { + required_providers { + slack = { + source = "pablovarela/slack" + version = "~> 1.0" + } + } +} + +variable "data_sources" { + default = { + tsc_members_user_ids = [] + maintainers_user_ids = [] + repo_maintainers = {} + } + description = "Data sources for the slack channels from the users module" +} + +locals { + channel_data = yamldecode(file("${path.module}/channels.yaml")) + channels = { + for channel in local.channel_data : channel.name => { + name = channel.name + topic = channel.topic + purpose = channel.purpose + + # if permanent_members is not provided, then it wil be taken from local with the name in data sources + permanent_members = lookup(channel, "permanent_members", lookup(var.data_sources, lookup(channel, "data_source", channel.name), [])) + is_private = channel.is_private + action_on_destroy = channel.action_on_destroy + + # if private channel, then kick all users on update else none + action_on_update_permanent_members = channel.is_private ? "kick" : "none" + adopt_existing_channel = true + } + } +} + +resource "slack_conversation" "channels" { + for_each = local.channels + name = each.value.name + topic = each.value.topic + purpose = each.value.purpose + permanent_members = each.value.permanent_members + + is_private = each.value.is_private + action_on_destroy = each.value.action_on_destroy + action_on_update_permanent_members = each.value.action_on_update_permanent_members + adopt_existing_channel = each.value.adopt_existing_channel +} + +locals { + working_groups_data = yamldecode(file("${path.module}/../../../../WORKING_GROUPS.yaml")).working_groups + wg_channels = { + for wg_data in local.working_groups_data : wg_data.name => { + name = lookup(lookup(lookup(wg_data, "slack", {}), "channel", {}), "handle", "wg-${replace(lower(wg_data.name), " ", "-")}") + purpose = lookup(lookup(lookup(wg_data, "slack", {}), "channel", {}), "description", lookup(wg_data, "description", "")) + topic = lookup(lookup(lookup(wg_data, "slack", {}), "channel", {}), "topic", "") + + permanent_members = concat([for member in wg_data.chairpersons : member.slack], [for member in wg_data.members : member.slack]) + is_private = false + + action_on_destroy = "archive" + action_on_update_permanent_members = "none" + adopt_existing_channel = true + } + } +} + +resource "slack_conversation" "wg_channels" { + for_each = local.wg_channels + name = each.value.name + topic = each.value.topic + purpose = each.value.purpose + permanent_members = each.value.permanent_members + + is_private = each.value.is_private + action_on_destroy = each.value.action_on_destroy + action_on_update_permanent_members = each.value.action_on_update_permanent_members + adopt_existing_channel = each.value.adopt_existing_channel +} + +output "wg_channels" { + value = slack_conversation.wg_channels +} \ No newline at end of file diff --git a/.github/workflows/slack/channels/channels.yaml b/.github/workflows/slack/channels/channels.yaml new file mode 100644 index 000000000..861911a19 --- /dev/null +++ b/.github/workflows/slack/channels/channels.yaml @@ -0,0 +1,255 @@ +# Channels: +# +# name - (Required) name of the public or private channel. +# topic - (Optional) topic for the channel. +# purpose - (Optional) purpose of the channel. +# permanent_members - (Optional) user IDs to add to the channel. +# is_private - (Optional) create a private channel instead of a public one. +# is_archived - (Optional) indicates a conversation is archived. Frozen in time. +# action_on_destroy - (Optional, Default archive) indicates whether the conversation should be archived or left behind on destroy. Valid values are archive | none. Note that when set to none the conversation will be left as it is and as a result any subsequent runs of terraform apply with the same name will fail. +# data_source - (Optional) data_source source to use for the list of user IDs to add to the channel. Valid values are maintainers_user_ids | tsc_user_ids right now. + +# NOTE:- +# 1. The channel name should be unique. +# 2. The user IDs should be valid and should be present in the workspace. +# 3. Either permanent_members or data_source should be provided to add users to the channel. +# 4. The default value for change in permanent_members is kick for private channels and nothing for public channels. +# 5. The default value for adopt_current_channels is true. + +- name: 01_introductions + topic: Welcome to our AsyncAPI Slack! Take a moment to introduce yourself. + purpose: Welcome to our AsyncAPI Slack! Take a moment to introduce yourself. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 02_general + topic: 'Talk here if your topic is not only about the spec, nor tools but kinda mix and involves AsyncAPI :slightly_smiling_face:' + purpose: This channel is for team-wide communication and announcements. All team members are in this channel. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 03_specification + topic: All around the spec discussions. It is ok to ask for support here. + purpose: All around the spec discussions. It is ok to ask for support here. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 04_tooling + topic: All around the specs tooling discussions. It is ok to ask for support here. + purpose: Chat about the AsyncAPI tooling + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 05_promotion-marketing + topic: Purpose of this channel is to help us with AsyncAPI promotion. Share your ideas for marketing and learn what we are working on at the moment. We use “channel” annotation here when we want to ask you to share our specific resources on different media. + purpose: Present launch plans for coordinated launches and to measure engagement and adoption + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 06_training + topic: All about trainings, workshops, courses, etc. — + purpose: All about trainings, workshops, courses, etc. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 07_events + topic: This is the place where we regroup and discuss organization of AsyncAPI-related events. This is also a place where you can always let others know what events are you involved in, where and when do you present a topic related to AsyncAPI. + purpose: This is the place where we regroup and discuss organization of AsyncAPI-related events. This is also a place where you can always let others know what events are you involved in, where and when do you present a topic related to AsyncAPI. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 08_jobs + topic: Looking for a job that will let you work on AsyncAPI? Let others know. Looking for AsyncAPI expert to join your company, post your offer here and also on the AsyncAPI website . + purpose: Looking for a job that will let you work on AsyncAPI? Let others know. Looking for AsyncAPI expert to join your company, post your offer here and also on the AsyncAPI website . + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 09_mentorships + topic: We participate in many different external programs, and also have our own that will evolve in next years. This is the place where we talk about these and coordinate. + purpose: We participate in many different external programs, and also have our own that will evolve in next years. This is the place where we talk about these and coordinate. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 10_watercooler + topic: Non-AsyncAPI topics. When you have a need to talk to someone “in person”, type “/zoom” in channel and start a meeting and let others know you are there. Talking to another human solves many problems. + purpose: A place for non-work-related flimflam, faffing, hodge-podge or jibber-jabber you'd prefer to keep out of more focused work-related channels. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 11_contributing + topic: Learn how to contribute. Ask contribution-related questions. Tell us what you want to learn through contribution and we will find you a good spot. Remember that you can contribute not only by pushing code. + purpose: Learn how to contribute. Share what you would like to learn and we will find for you a good place to start contributing + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 12_design + topic: Discuss design-related topics such as branding, design system, UI kit, and any other misc. design projects. Have a design request? Use this channel to propose and discuss your request! + purpose: Discuss design-related topics such as branding, design system, UI kit, and any other misc. design projects. Have a design request? Use this channel to propose and discuss your request! + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 13_docs + topic: null + purpose: ':bookmark_tabs: Discuss AsyncAPI Docs: Feel free to open issues for documentation requests and to share ideas/feedback on open issues. ' + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 14_accessibility + topic: Accessibility throughout the asyncAPI Initiative + purpose: Accessibility throughout the AsyncAPI Initiative + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 15_ambassadors + topic: null + purpose: All about the Ambassador Program. Feel free to participate! + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 16_news + topic: null + purpose: Share links to news you find about AsyncAPI (or related stuff) on the internet. Did you write something and want us to help you promote it? Use the <#CH44ZMJAZ|05_promotion-marketing> channel instead. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 17_bounty + topic: All about the AsyncAPI Bounty Program discussions. + purpose: This is the place where we discuss everything related to the Bounty Program. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 18_asyncapi-v3 + topic: This is the channel where we talk about AsyncAPI v3. From announcements, blogs, and livestreams. + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 19_coc + topic: null + purpose: Feel free to openly ask the Code of Conduct Committee if you have any questions. + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 93_bot-infra-alerts + topic: null + purpose: Alerts on infrastructure monitoring (New Relic by now) + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 94_bot-failing-ci + topic: null + purpose: When something wrong happens in CI and we configure Slack alerts - these should end up in this channel + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 95_bot-tsc-members-mentioned + topic: This channel is here to mainly help TSC members to get notifications other than email or GitHub notifications, every time TSC GitHub team is mentioned in issues, PRs and discussions + purpose: This channel is here to mainly help TSC members to get notifications other than email or GitHub notifications, every time TSC GitHub team is mentioned in issues, PRs and discussions + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 96_bot-stackoverflow-questions + topic: Stackoverflow questions tagged asyncapi from the RSS feed + purpose: Stackoverflow questions tagged `asyncapi` from the RSS feed + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 97_bot-github-new-issues-prs + topic: Bot sends notifications about every new issue and pull request in any AsyncAPI repository. + purpose: Notifications about all new issues and PR except of bots + is_private: false + is_archived: false + action_on_destroy: archive + +- name: 98_bot-github-releases + topic: Bot sends notifications about every new release in any AsyncAPI repository. + purpose: Notifications about new GitHub releases + is_private: false + is_archived: false + action_on_destroy: archive + +- name: glee-demos + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: gsoc2021-students-mentors-collaboration + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: help- + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: jsonschema + topic: 'Need help with JSON Schema? This channel is connected with the JSON Schema Slack workspace. Here you can talk with the JSON Schema community directly :raised_hands:' + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: libopenapi-speakeasy + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: linux + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: salemfr1100 + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: status-updates + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive + +- name: test-bot-public + topic: null + purpose: null + is_private: false + is_archived: false + action_on_destroy: archive diff --git a/.github/workflows/slack/groups/groups.tf b/.github/workflows/slack/groups/groups.tf new file mode 100644 index 000000000..9438fa7ec --- /dev/null +++ b/.github/workflows/slack/groups/groups.tf @@ -0,0 +1,74 @@ +terraform { + required_providers { + slack = { + source = "pablovarela/slack" + version = "~> 1.0" + } + } +} + +variable "wg_channels" { + description = "Map of working group channels" +} + +variable "data_sources" { + default = { + tsc_members_user_ids = [] + maintainers_user_ids = [] + repo_maintainers = {} + } + description = "Data sources for the slack groups from the users module" +} + +locals { + group_data = yamldecode(file("${path.module}/groups.yaml")) + groups = { + for group in local.group_data : group.name => { + name = group.name + handle = group.handle + description = group.description + users = lookup(group, "users", lookup(var.data_sources, lookup(group, "data_source", group.name), [])) + channels = lookup(group, "channels", []) + } + } +} + +resource "slack_usergroup" "groups" { + for_each = local.groups + name = each.value.name + handle = each.value.handle + description = each.value.description + users = each.value.users + channels = each.value.channels +} + +resource "slack_usergroup" "maintainer_repos" { + for_each = var.data_sources.repo_maintainers + name = "Maintainers of asyncapi/${each.key}" + handle = "maintainers_${each.key}" + description = "Maintainers for https://github.com/asyncapi/${each.key}" + users = each.value +} + +locals { + working_groups_data = yamldecode(file("${path.module}/../../../../WORKING_GROUPS.yaml")).working_groups + wg_groups = { + for wg_data in local.working_groups_data : wg_data.name => { + name = lookup(lookup(lookup(wg_data, "slack", {}), "group", {}), "name", wg_data.name) + description = lookup(lookup(lookup(wg_data, "slack", {}), "group", {}), "description", lookup(wg_data, "description", "")) + + # Handle will be the name of the group in lowercase and with spaces replaced by hyphens succeded by "wg-" + handle = lookup(lookup(lookup(wg_data, "slack", {}), "group", {}), "handle", "${replace(lower(wg_data.name), " ", "-")}-wg") + users = concat([for member in wg_data.chairpersons : member.slack], [for member in wg_data.members : member.slack]) + } + } +} + +resource "slack_usergroup" "wg_groups" { + for_each = local.wg_groups + name = each.value.name + handle = each.value.handle + description = each.value.description + users = each.value.users + channels = [var.wg_channels[each.value.name].id] +} \ No newline at end of file diff --git a/.github/workflows/slack/groups/groups.yaml b/.github/workflows/slack/groups/groups.yaml new file mode 100644 index 000000000..35a5695ef --- /dev/null +++ b/.github/workflows/slack/groups/groups.yaml @@ -0,0 +1,53 @@ +# - Groups: +# - name: (Required) The name of the user group. +# - handle: (Required) A name for the user group that is unique among channels, users, and user groups. +# - description: (Optional) A short description of the user group. +# - users: (Optional) A list of user IDs that are part of the user group. +# - data_source: (Optional) The data source to use for the user group. If users is not provided, the user group will be populated with users from the data source. +# - channels: (Optional) A list of channel IDs for channels that the user group will be in. + +# IMPORTANT: Once a user group is created it cannot be deleted. And an existing user group cannot be created again. +# Before adding them here please make sure to import them like this: +# terraform import slack_usergroup. + +- name: "TSC Members" + handle: "tsc" + description: "TSC members - https://www.asyncapi.com/community/tsc" + data_source: "tsc_members_user_ids" + +- name: "Maintainers" + handle: "maintainers" + description: "Maintainers" + data_source: "maintainers_user_ids" + +- name: "Studio" + handle: "studio" + description: "To notify all regular Studio contributors at once. If you don't contribute regularly but want to get notified too, please open a PR to get added." + users: + - "U01RWDD69PZ" + - "U0572R8J927" + - "U058PQFJPS4" + - "U01RVRD1TCL" + - "U01EB02BP7A" + - "U01TP1KJV1R" + - "U04STTQHV18" + - "U01N6AW5V5G" + - "U01SGCZMJKW" + channels: + - "CQVJXFNQL" + - "C02JW8DA0DC" + + +- name: "CoC Committee" + handle: "coc_committee" + description: "To notify the code of conduct team all at once when there is a question or anything related to them." + users: + - "U01RWDD69PZ" + - "U01J42QDSLU" + - "U03CNHGEUR1" + - "UN22ZTLHG" + - "U03CNJPMT7C" + - "U02AKC14WAJ" + channels: + - "C06FLH3AVSB" + - "C06CQCK03EJ" \ No newline at end of file diff --git a/.github/workflows/slack/slack.tf b/.github/workflows/slack/slack.tf new file mode 100644 index 000000000..98667ddc3 --- /dev/null +++ b/.github/workflows/slack/slack.tf @@ -0,0 +1,36 @@ +terraform { + required_providers { + slack = { + source = "pablovarela/slack" + version = "~> 1.0" + } + } + required_version = ">= 0.13" +} + +variable "slack_token" { + description = "The Slack API token with the channels:manage, channels:read, channels:write.invites, groups:read, groups:write, groups:write.invites, users:read scopes" + nullable = false + type = string +} + +provider "slack" { + token = var.slack_token +} + +module "users" { + source = "./users" +} + +module "channels" { + source = "./channels" + depends_on = [ module.users ] + data_sources = module.users.data_sources +} + +module "groups" { + source = "./groups" + depends_on = [ module.users, module.channels ] + data_sources = module.users.data_sources + wg_channels = module.channels.wg_channels +} \ No newline at end of file diff --git a/.github/workflows/slack/terraform.tfstate b/.github/workflows/slack/terraform.tfstate new file mode 100644 index 000000000..103451375 --- /dev/null +++ b/.github/workflows/slack/terraform.tfstate @@ -0,0 +1,999 @@ +{ + "version": 4, + "terraform_version": "1.7.1", + "serial": 40, + "lineage": "be714778-98f8-035d-1a6d-5aecc493dcb2", + "outputs": {}, + "resources": [ + { + "module": "module.channels", + "mode": "managed", + "type": "slack_conversation", + "name": "channels", + "provider": "provider[\"registry.terraform.io/pablovarela/slack\"]", + "instances": [ + { + "index_key": "01_introductions", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1622040350, + "creator": "UD698Q5LM", + "id": "C023GJWH33K", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "01_introductions", + "permanent_members": null, + "purpose": "Welcome to our AsyncAPI Slack! Take a moment to introduce yourself.", + "topic": "Welcome to our AsyncAPI Slack! Take a moment to introduce yourself." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "02_general", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1479472560, + "creator": "U34F2JRRS", + "id": "C34F2JV0U", + "is_archived": false, + "is_ext_shared": false, + "is_general": true, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "02_general", + "permanent_members": null, + "purpose": "This channel is for team-wide communication and announcements. All team members are in this channel.", + "topic": "Talk here if your topic is not only about the spec, nor tools but kinda mix and involves AsyncAPI :slightly_smiling_face:" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "03_specification", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1622040521, + "creator": "UD698Q5LM", + "id": "C0230UAM6R3", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "03_specification", + "permanent_members": null, + "purpose": "All around the spec discussions. It is ok to ask for support here.", + "topic": "All around the spec discussions. It is ok to ask for support here." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "04_tooling", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1574451424, + "creator": "U34F2JRRS", + "id": "CQVJXFNQL", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "04_tooling", + "permanent_members": null, + "purpose": "Chat about the AsyncAPI tooling", + "topic": "All around the specs tooling discussions. It is ok to ask for support here." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "05_promotion-marketing", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1553016525, + "creator": "UC3B0355Z", + "id": "CH44ZMJAZ", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "05_promotion-marketing", + "permanent_members": null, + "purpose": "Present launch plans for coordinated launches and to measure engagement and adoption", + "topic": "Purpose of this channel is to help us with AsyncAPI promotion. Share your ideas for marketing and learn what we are working on at the moment. We use “channel” annotation here when we want to ask you to share our specific resources on different media." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "06_training", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1620649432, + "creator": "U34F2JRRS", + "id": "C021E161QBV", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "06_training", + "permanent_members": null, + "purpose": "All about trainings, workshops, courses, etc.", + "topic": "All about trainings, workshops, courses, etc. — \u003chttps://github.com/asyncapi/training\u003e" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "07_events", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1622040979, + "creator": "UD698Q5LM", + "id": "C023A76SV2Q", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "07_events", + "permanent_members": null, + "purpose": "This is the place where we regroup and discuss organization of AsyncAPI-related events. This is also a place where you can always let others know what events are you involved in, where and when do you present a topic related to AsyncAPI.", + "topic": "This is the place where we regroup and discuss organization of AsyncAPI-related events. This is also a place where you can always let others know what events are you involved in, where and when do you present a topic related to AsyncAPI." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "08_jobs", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1622041069, + "creator": "UD698Q5LM", + "id": "C022P9CAMBR", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "08_jobs", + "permanent_members": null, + "purpose": "Looking for a job that will let you work on AsyncAPI? Let others know. Looking for AsyncAPI expert to join your company, post your offer here and also on the AsyncAPI website \u003chttps://www.asyncapi.com/jobs\u003e.", + "topic": "Looking for a job that will let you work on AsyncAPI? Let others know. Looking for AsyncAPI expert to join your company, post your offer here and also on the AsyncAPI website \u003chttps://www.asyncapi.com/jobs\u003e." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "09_mentorships", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1622041116, + "creator": "UD698Q5LM", + "id": "C023A7K5M3N", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "09_mentorships", + "permanent_members": null, + "purpose": "We participate in many different external programs, and also have our own that will evolve in next years. This is the place where we talk about these and coordinate.", + "topic": "We participate in many different external programs, and also have our own that will evolve in next years. This is the place where we talk about these and coordinate." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "10_watercooler", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1479472560, + "creator": "U34F2JRRS", + "id": "C34AUKWQK", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "10_watercooler", + "permanent_members": null, + "purpose": "A place for non-work-related flimflam, faffing, hodge-podge or jibber-jabber you'd prefer to keep out of more focused work-related channels.", + "topic": "Non-AsyncAPI topics. When you have a need to talk to someone “in person”, type “/zoom” in channel and start a meeting and let others know you are there. Talking to another human solves many problems." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "11_contributing", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1632379587, + "creator": "UD698Q5LM", + "id": "C02FK3YDPCL", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "11_contributing", + "permanent_members": null, + "purpose": "Learn how to contribute. Share what you would like to learn and we will find for you a good place to start contributing", + "topic": "Learn how to contribute. Ask contribution-related questions. Tell us what you want to learn through contribution and we will find you a good spot. Remember that you can contribute not only by pushing code." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "12_design", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1635256181, + "creator": "UD698Q5LM", + "id": "C02JW8DA0DC", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "12_design", + "permanent_members": null, + "purpose": "Discuss design-related topics such as branding, design system, UI kit, and any other misc. design projects. Have a design request? Use this channel to propose and discuss your request!", + "topic": "Discuss design-related topics such as branding, design system, UI kit, and any other misc. design projects. Have a design request? Use this channel to propose and discuss your request!" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "13_docs", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1639621854, + "creator": "U02AKC14WAJ", + "id": "C02QY9FMM18", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "13_docs", + "permanent_members": null, + "purpose": ":bookmark_tabs: Discuss AsyncAPI Docs: Feel free to open issues for documentation requests and to share ideas/feedback on open issues. \u003chttps://github.com/orgs/asyncapi/projects/8\u003e", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "14_accessibility", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1642713336, + "creator": "U02AKC14WAJ", + "id": "C02UV8CTT61", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "14_accessibility", + "permanent_members": null, + "purpose": "Accessibility throughout the AsyncAPI Initiative", + "topic": "Accessibility throughout the asyncAPI Initiative" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "15_ambassadors", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1678796519, + "creator": "U01J42QDSLU", + "id": "C04TRUTNPHB", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "15_ambassadors", + "permanent_members": null, + "purpose": "All about the Ambassador Program. Feel free to participate!", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "16_news", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1693300530, + "creator": "U34F2JRRS", + "id": "C05PWURSSP7", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "16_news", + "permanent_members": null, + "purpose": "Share links to news you find about AsyncAPI (or related stuff) on the internet. Did you write something and want us to help you promote it? Use the \u003c#CH44ZMJAZ|05_promotion-marketing\u003e channel instead.", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "17_bounty", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1696235939, + "creator": "U03CNJPMT7C", + "id": "C05UHTSEHE2", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "17_bounty", + "permanent_members": null, + "purpose": "This is the place where we discuss everything related to the Bounty Program.", + "topic": "All about the AsyncAPI Bounty Program discussions." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "18_asyncapi-v3", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1700755885, + "creator": "U03CNJPMT7C", + "id": "C066WFT906A", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "18_asyncapi-v3", + "permanent_members": null, + "purpose": "", + "topic": "This is the channel where we talk about AsyncAPI v3. From announcements, blogs, and livestreams." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "19_coc", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1706519672, + "creator": "U03CNJPMT7C", + "id": "C06FLH3AVSB", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "19_coc", + "permanent_members": null, + "purpose": "Feel free to openly ask the Code of Conduct Committee if you have any questions.", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "93_bot-infra-alerts", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1665663760, + "creator": "UN22ZTLHG", + "id": "C045Y33BZQX", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "93_bot-infra-alerts", + "permanent_members": null, + "purpose": "Alerts on infrastructure monitoring (New Relic by now)", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "94_bot-failing-ci", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1650439390, + "creator": "UD698Q5LM", + "id": "C03CHT8UFR7", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "94_bot-failing-ci", + "permanent_members": null, + "purpose": "When something wrong happens in CI and we configure Slack alerts - these should end up in this channel", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "95_bot-tsc-members-mentioned", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1644233870, + "creator": "UD698Q5LM", + "id": "C031UMXT63F", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "95_bot-tsc-members-mentioned", + "permanent_members": null, + "purpose": "This channel is here to mainly help TSC members to get notifications other than email or GitHub notifications, every time TSC GitHub team is mentioned in issues, PRs and discussions", + "topic": "This channel is here to mainly help TSC members to get notifications other than email or GitHub notifications, every time TSC GitHub team is mentioned in issues, PRs and discussions" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "96_bot-stackoverflow-questions", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1623665010, + "creator": "U6C2X4W1K", + "id": "C02544TFYJ0", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "96_bot-stackoverflow-questions", + "permanent_members": null, + "purpose": "Stackoverflow questions tagged `asyncapi` from the RSS feed", + "topic": "Stackoverflow questions tagged asyncapi from the RSS feed" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "97_bot-github-new-issues-prs", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1610383119, + "creator": "UD698Q5LM", + "id": "C01J06RL10X", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "97_bot-github-new-issues-prs", + "permanent_members": null, + "purpose": "Notifications about all new issues and PR except of bots", + "topic": "Bot sends notifications about every new issue and pull request in any AsyncAPI repository." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "98_bot-github-releases", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1610383083, + "creator": "UD698Q5LM", + "id": "C01JF00UGKC", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "98_bot-github-releases", + "permanent_members": null, + "purpose": "Notifications about new GitHub releases", + "topic": "Bot sends notifications about every new release in any AsyncAPI repository." + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "glee-demos", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1635694344, + "creator": "U34F2JRRS", + "id": "C02L1QCT1HP", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "glee-demos", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "gsoc2021-students-mentors-collaboration", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1622528565, + "creator": "U01CUAY035J", + "id": "C023H9V3ZLM", + "is_archived": false, + "is_ext_shared": true, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": true, + "name": "gsoc2021-students-mentors-collaboration", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "help-", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1640505133, + "creator": "U02SNQYK43A", + "id": "C02RJF383MM", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "help-", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "jsonschema", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1648200854, + "creator": "U5CJT43D2", + "id": "C038FTU4LQ6", + "is_archived": false, + "is_ext_shared": true, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": true, + "name": "jsonschema", + "permanent_members": null, + "purpose": "", + "topic": "Need help with JSON Schema? This channel is connected with the JSON Schema Slack workspace. Here you can talk with the JSON Schema community directly :raised_hands:" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "libopenapi-speakeasy", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1671028791, + "creator": "U03R0RBGA7N", + "id": "C04F6TQ40N7", + "is_archived": false, + "is_ext_shared": true, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": true, + "name": "libopenapi-speakeasy", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "linux", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1670708349, + "creator": "U04F18KAZEV", + "id": "C04EKM39P4M", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "linux", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "salemfr1100", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1682892720, + "creator": "U04RSMQHJ66", + "id": "C055JEMLGF7", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "salemfr1100", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "status-updates", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1709725751, + "creator": "U34F2JRRS", + "id": "C06N61ASV6X", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "status-updates", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "test-bot-public", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1683823890, + "creator": "U01RVRD1TCL", + "id": "C0579CUA7GD", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "test-bot-public", + "permanent_members": null, + "purpose": "", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + } + ] + }, + { + "module": "module.channels", + "mode": "managed", + "type": "slack_conversation", + "name": "wg_channels", + "provider": "provider[\"registry.terraform.io/pablovarela/slack\"]", + "instances": [ + { + "index_key": "Developer Experience", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1706786192, + "creator": "U34F2JRRS", + "id": "C06G92DN05D", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "wg-developer-experience", + "permanent_members": null, + "purpose": "The goal of this group is to empower AsyncAPI user journey trough intuitive onboarding, tools, and a frictionless experience.", + "topic": "Current Roadmap: \u003chttps://shapeit.app/projects/org/asyncapi/16/cycles/ceb40c9d?issue=I_kwDOLQFNzc5-xigF\u003e" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + }, + { + "index_key": "Essential Building Blocks", + "schema_version": 0, + "attributes": { + "action_on_destroy": null, + "action_on_update_permanent_members": null, + "adopt_existing_channel": null, + "created": 1712225888, + "creator": "U03CNJPMT7C", + "id": "C06SSB65QQJ", + "is_archived": false, + "is_ext_shared": false, + "is_general": false, + "is_org_shared": false, + "is_private": false, + "is_shared": false, + "name": "wg-essential-building-blocks", + "permanent_members": null, + "purpose": "The goal of the Essential Building Blocks Working Group is to provide fundamental building blocks that enable a similar developer experience across different languages. GitHub Project: \u003chttps://github.com/orgs/asyncapi/projects/44\u003e", + "topic": "" + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==" + } + ] + }, + { + "module": "module.groups", + "mode": "managed", + "type": "slack_usergroup", + "name": "groups", + "provider": "provider[\"registry.terraform.io/pablovarela/slack\"]", + "instances": [ + { + "index_key": "CoC Committee", + "schema_version": 0, + "attributes": { + "channels": [ + "C06CQCK03EJ", + "C06FLH3AVSB" + ], + "description": "To notify the code of conduct team all at once when there is a question or anything related to them.", + "handle": "coc_committee", + "id": "S06G3VCDTPU", + "name": "CoC Committee", + "users": [ + "U01J42QDSLU", + "U01RWDD69PZ", + "U02AKC14WAJ", + "U03CNHGEUR1", + "U03CNJPMT7C", + "UN22ZTLHG" + ] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==", + "dependencies": [ + "module.channels.slack_conversation.channels", + "module.channels.slack_conversation.wg_channels" + ] + }, + { + "index_key": "Studio", + "schema_version": 0, + "attributes": { + "channels": [ + "C02JW8DA0DC", + "CQVJXFNQL" + ], + "description": "To notify all regular Studio contributors at once. If you don't contribute regularly but want to get notified too, ping Fran to get added.", + "handle": "studio", + "id": "S05D76QM92M", + "name": "Studio", + "users": [ + "U01EB02BP7A", + "U01N6AW5V5G", + "U01RVRD1TCL", + "U01RWDD69PZ", + "U01SGCZMJKW", + "U01TP1KJV1R", + "U04STTQHV18", + "U0572R8J927", + "U058PQFJPS4" + ] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==", + "dependencies": [ + "module.channels.slack_conversation.channels", + "module.channels.slack_conversation.wg_channels" + ] + } + ] + }, + { + "module": "module.groups", + "mode": "managed", + "type": "slack_usergroup", + "name": "wg_groups", + "provider": "provider[\"registry.terraform.io/pablovarela/slack\"]", + "instances": [ + { + "index_key": "Developer Experience", + "schema_version": 0, + "attributes": { + "channels": [ + "C06G92DN05D" + ], + "description": "The Developer Experience Working Group", + "handle": "dx_wg", + "id": "S06T4ULNQL8", + "name": "Developer Experience Working Group", + "users": [ + "U0132LQU8C9", + "U01N6AW5V5G", + "U01RVRD1TCL", + "U01TP1KJV1R", + "U03CNHGEUR1", + "U04STTQHV18", + "U0572R8J927", + "U34F2JRRS", + "UTCN3ET4M" + ] + }, + "sensitive_attributes": [], + "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjAifQ==", + "dependencies": [ + "module.channels.slack_conversation.channels", + "module.channels.slack_conversation.wg_channels" + ] + } + ] + } + ], + "check_results": null +} diff --git a/.github/workflows/slack/users/users.tf b/.github/workflows/slack/users/users.tf new file mode 100644 index 000000000..4fa16dc9e --- /dev/null +++ b/.github/workflows/slack/users/users.tf @@ -0,0 +1,30 @@ +terraform { + required_providers { + slack = { + source = "pablovarela/slack" + version = "~> 1.0" + } + } +} + +locals { + maintainers_data = yamldecode(file("${path.root}/../../../MAINTAINERS.yaml")) + + # maintainers with isTscMember = true are added to the tsc_members group + tsc_members_data = [for maintainer in local.maintainers_data : maintainer if lookup(maintainer, "isTscMember", false) == true] + + # Make a map of repo maintainers with their slack user id with repo name as key + repos = setunion(flatten([for maintainer in local.maintainers_data : maintainer.repos])) + repo_maintainers = { + for repo in local.repos : repo => + [for maintainer in local.maintainers_data : maintainer.slack if contains(maintainer.repos, repo)] + } +} + +output "data_sources" { + value = { + maintainers_user_ids = [for maintainer in local.maintainers_data : maintainer.slack] + tsc_members_user_ids = [for tsc_member in local.tsc_members_data : tsc_member.slack] + repo_maintainers = local.repo_maintainers + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index b512c09d4..b0f0a309f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -node_modules \ No newline at end of file +node_modules +.terraform +*tfstate.backup +*.tfvars \ No newline at end of file diff --git a/TSC_MEMBERSHIP.md b/TSC_MEMBERSHIP.md index ef33c56d8..73373b9bd 100644 --- a/TSC_MEMBERSHIP.md +++ b/TSC_MEMBERSHIP.md @@ -49,3 +49,12 @@ Joining the TSC is something that you are allowed to do as a maintainer by defau See current [TSC members](https://www.asyncapi.com/community/tsc). +## How to reach out to the TSC + +There are several ways to reach out to the TSC members: + +* Join the [AsyncAPI Slack](https://www.asyncapi.com/slack-invite) and ping the `@tsc` group to ask questions or share your thoughts. +* Do a GitHub team mention `@asyncapi/tsc_members` in any issue, discussion or pull request. This will also send a message in the `95_bot-tsc-members-mentioned` channel in the Slack. + +> [!IMPORTANT] +> Please note that the TSC members are volunteers and may not be able to respond immediately. Please be patient and respectful. Also it will be helpful if there is as less spam as possible. For more information, please refer to the [Slack Etiquette](./slack-etiquette.md) document. diff --git a/WORKING_GROUPS.md b/WORKING_GROUPS.md index faee48724..5299421c6 100644 --- a/WORKING_GROUPS.md +++ b/WORKING_GROUPS.md @@ -19,3 +19,14 @@ A Working Group must discuss ideas and solutions in public, and communicate thro It is recommended that the Working Group schedules meetings using the methods described at https://github.com/asyncapi/community/blob/master/MEETINGS_ORGANIZATION.md. Working Groups should be listed on the [AsyncAPI website](https://www.asyncapi.com), along with their description, goals, members, and anything the Working Group wants to include. + +### How to reach out to a Working Group + +There are several ways to reach out to a Working Group: + +- Join the [AsyncAPI Slack](https://www.asyncapi.com/slack-invite) and ping the working group's handle to ask questions or share your thoughts. The handle can be found in the [WORKING_GROUPS.yaml](./WORKING_GROUPS.yaml) file in the `slack.group.handle` field. Example: `@dx_wg`. +- Do a GitHub team mention in any issue, discussion, or pull request. The team handle can be found in the [WORKING_GROUPS.yaml](./WORKING_GROUPS.yaml) file in `github_team` field. Example: `developer_experience_wg`. +- Join the working group's channel on Slack. The channel name can be found in the [WORKING_GROUPS.yaml](./WORKING_GROUPS.yaml) file in the `slack.channel.handle` field. Example: `#wg-developer-experience`. + +> [!IMPORTANT] +> Please note that the Working Group members are volunteers and may not be able to respond immediately. Please be patient and respectful. Also, it will be helpful if there is as little spam as possible. For more information, please refer to the [Slack Etiquette](./slack-etiquette.md) document. \ No newline at end of file diff --git a/WORKING_GROUPS.yaml b/WORKING_GROUPS.yaml index bebf9fbcc..a75a1c441 100644 --- a/WORKING_GROUPS.yaml +++ b/WORKING_GROUPS.yaml @@ -51,7 +51,7 @@ working_groups: slack: channel: handle: wg-essential-building-blocks - description: 'The goal of the Essential Building Blocks Working Group is to provide fundamental building blocks that enable a similar developer experience across different languages. GitHub Project: https://github.com/orgs/asyncapi/projects/44' + description: 'The goal of the Essential Building Blocks Working Group is to provide fundamental building blocks that enable a similar developer experience across different languages. GitHub Project: ' group: handle: essential-building-blocks-wg description: Essential Building Blocks Working Group @@ -95,9 +95,9 @@ working_groups: channel: handle: wg-developer-experience description: 'The goal of this group is to empower AsyncAPI user journey trough intuitive onboarding, tools, and a frictionless experience.' - topic: 'Current Roadmap: https://shapeit.app/projects/org/asyncapi/16/cycles/ceb40c9d?issue=I_kwDOLQFNzc5-xigF' - group: - handle: wg-dx + topic: 'Current Roadmap: ' + group: + handle: dx_wg roadmap_url: https://shapeit.app/projects/org/asyncapi/16 objectives: - https://github.com/users/Amzani/projects/12/views/1