diff --git a/.github/scripts/maintainers/.gitignore b/.github/scripts/maintainers/.gitignore
new file mode 100644
index 000000000..60923f546
--- /dev/null
+++ b/.github/scripts/maintainers/.gitignore
@@ -0,0 +1 @@
+github.api.cache.json
diff --git a/.github/scripts/maintainers/README.md b/.github/scripts/maintainers/README.md
new file mode 100644
index 000000000..6d82e01e4
--- /dev/null
+++ b/.github/scripts/maintainers/README.md
@@ -0,0 +1,58 @@
+# Maintainers
+
+The ["Update MAINTAINERS.yaml file"](../../workflows/update-maintainers.yaml) workflow, defined in the `community` repository performs a complete refresh by fetching all public repositories under AsyncAPI and their respective `CODEOWNERS` files.
+
+## Workflow Execution
+
+The "Update MAINTAINERS.yaml file" workflow is executed in the following scenarios:
+
+1. **Weekly Schedule**: The workflow runs automatically every week. It is useful, e.g. when some repositories are archived, renamed, or when a GitHub user account is removed.
+2. **On Change**: When a `CODEOWNERS` file is changed in any repository under the AsyncAPI organization, the related repository triggers the workflow by emitting the `trigger-maintainers-update` event.
+3. **Manual Trigger**: Users can manually trigger the workflow as needed.
+
+### Workflow Steps
+
+1. **Load Cache**: Attempt to read previously cached data from `github.api.cache.json` to optimize API calls.
+2. **List All Repositories**: Retrieve a list of all public repositories under the AsyncAPI organization, skipping any repositories specified in the `IGNORED_REPOSITORIES` environment variable.
+3. **Fetch `CODEOWNERS` Files**: For each repository:
+ - Detect the default branch (e.g., `main`, `master`, or a custom branch).
+ - Check for `CODEOWNERS` files in all valid locations as specified in the [GitHub documentation](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-file-location).
+4. **Process `CODEOWNERS` Files**:
+ 1. Extract GitHub usernames from each `CODEOWNERS` file, excluding emails, team names, and users specified by the `IGNORED_USERS` environment variable.
+ 2. Retrieve profile information for each unique GitHub username.
+ 3. Collect a fresh list of repositories currently owned by each GitHub user.
+5. **Refresh Maintainers List**: Iterate through the existing maintainers list:
+ - Delete the entry if it:
+ - Refers to a deleted GitHub account.
+ - Was not found in any `CODEOWNERS` file across all repositories in the AsyncAPI organization.
+ - Otherwise, update **only** the `repos` property.
+6. **Add New Maintainers**: Append any new maintainers not present in the previous list.
+7. **Changes Summary**: Provide details on why a maintainer was removed or changed directly on the GitHub Action [summary page](https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/).
+8. **Save Cache**: Save retrieved data in `github.api.cache.json`.
+
+## Job Details
+
+- **Concurrency**: Ensures the workflow does not run multiple times concurrently to avoid conflicts.
+- **Wait for PRs to be Merged**: The workflow waits for pending pull requests to be merged before execution. If the merged pull request addresses all necessary fixes, it prevents unnecessary executions.
+
+## Handling Conflicts
+
+Since the job performs a full refresh each time, resolving conflicts is straightforward:
+
+1. Close the pull request with conflicts.
+2. Navigate to the "Update MAINTAINERS.yaml file" workflow.
+3. Trigger it manually by clicking "Run workflow".
+
+## Caching Mechanism
+
+Each execution of this action performs a full refresh through the following API calls:
+
+```
+ListRepos(AsyncAPI) # 1 call using GraphQL - not cached.
+ for each Repo
+ GetCodeownersFile(Repo) # N calls using REST API - all are cached. N refers to the number of public repositories under AsyncAPI.
+ for each codeowner
+ GetGitHubProfile(owner) # Y calls using REST API - all are cached. Y refers to unique GitHub users found across all CODEOWNERS files.
+```
+
+To avoid hitting the GitHub API rate limits, [conditional requests](https://docs.github.com/en/rest/using-the-rest-api/best-practices-for-using-the-rest-api?apiVersion=2022-11-28#use-conditional-requests-if-appropriate) are used via `if-modified-since`. The API responses are saved into a `github.api.cache.json` file, which is later uploaded as a GitHub action cache item.
diff --git a/.github/scripts/maintainers/cache.js b/.github/scripts/maintainers/cache.js
new file mode 100644
index 000000000..0a52b4b7e
--- /dev/null
+++ b/.github/scripts/maintainers/cache.js
@@ -0,0 +1,64 @@
+const fs = require("fs");
+
+module.exports = {
+ fetchWithCache,
+ saveCache,
+ loadCache,
+ printAPICallsStats,
+};
+
+const CODEOWNERS_CACHE_PATH = "./.github/scripts/maintainers/github.api.cache.json";
+
+let cacheEntries = {};
+
+let numberOfFullFetches = 0;
+let numberOfCacheHits = 0;
+
+function loadCache(core) {
+ try {
+ cacheEntries = JSON.parse(fs.readFileSync(CODEOWNERS_CACHE_PATH, "utf8"));
+ } catch (error) {
+ core.warning(`Cache was not restored: ${error}`);
+ }
+}
+
+function saveCache() {
+ fs.writeFileSync(CODEOWNERS_CACHE_PATH, JSON.stringify(cacheEntries));
+}
+
+async function fetchWithCache(cacheKey, fetchFn, core) {
+ const cachedResp = cacheEntries[cacheKey];
+
+ try {
+ const { data, headers } = await fetchFn({
+ headers: {
+ "if-modified-since": cachedResp?.lastModified ?? "",
+ },
+ });
+
+ cacheEntries[cacheKey] = {
+ // last modified header is more reliable than etag while executing calls on GitHub Action
+ lastModified: headers["last-modified"],
+ data,
+ };
+
+ numberOfFullFetches++;
+ return data;
+ } catch (error) {
+ if (error.status === 304) {
+ numberOfCacheHits++;
+ core.debug(`Returning cached data for ${cacheKey}`);
+ return cachedResp.data;
+ }
+ throw error;
+ }
+}
+
+function printAPICallsStats(core) {
+ core.startGroup("API calls statistic");
+ core.info(
+ `Number of API calls count against rate limit: ${numberOfFullFetches}`,
+ );
+ core.info(`Number of cache hits: ${numberOfCacheHits}`);
+ core.endGroup();
+}
diff --git a/.github/scripts/maintainers/gh_calls.js b/.github/scripts/maintainers/gh_calls.js
new file mode 100644
index 000000000..f10b5c2eb
--- /dev/null
+++ b/.github/scripts/maintainers/gh_calls.js
@@ -0,0 +1,131 @@
+const { fetchWithCache } = require("./cache");
+
+module.exports = { getGitHubProfile, getAllCodeownersFiles, getRepositories };
+
+async function getRepositories(github, owner, ignoredRepos, core) {
+ core.startGroup(
+ `Getting list of all public, non-archived repositories owned by ${owner}`,
+ );
+
+ const query = `
+ query repos($cursor: String, $owner: String!) {
+ organization(login: $owner) {
+ repositories(first: 100 after: $cursor visibility: PUBLIC isArchived: false orderBy: {field: CREATED_AT, direction: ASC} ) {
+ nodes {
+ name
+ }
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ }
+ }
+ }`;
+
+ const repos = [];
+ let cursor = null;
+
+ do {
+ const result = await github.graphql(query, { owner, cursor });
+ const { nodes, pageInfo } = result.organization.repositories;
+ repos.push(...nodes);
+
+ cursor = pageInfo.hasNextPage ? pageInfo.endCursor : null;
+ } while (cursor);
+
+ core.debug(`List of repositories for ${owner}:`);
+ core.debug(JSON.stringify(repos, null, 2));
+ core.endGroup();
+
+ return repos.filter((repo) => !ignoredRepos.includes(repo.name));
+}
+
+async function getGitHubProfile(github, login, core) {
+ try {
+ const profile = await fetchWithCache(
+ `profile:${login}`,
+ async ({ headers }) => {
+ return github.rest.users.getByUsername({
+ username: login,
+ headers,
+ });
+ },
+ core,
+ );
+ return removeNulls({
+ name: profile.name ?? login,
+ github: login,
+ twitter: profile.twitter_username,
+ availableForHire: profile.hireable,
+ isTscMember: false,
+ repos: [],
+ githubID: profile.id,
+ });
+ } catch (error) {
+ if (error.status === 404) {
+ return null;
+ }
+ throw error;
+ }
+}
+
+// Checks for all valid locations according to:
+// https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-file-location
+//
+// Detect the repository default branch automatically.
+async function getCodeownersFile(github, owner, repo, core) {
+ const paths = ["CODEOWNERS", "docs/CODEOWNERS", ".github/CODEOWNERS"];
+
+ for (const path of paths) {
+ try {
+ core.debug(
+ `[repo: ${owner}/${repo}]: Fetching CODEOWNERS file at ${path}`,
+ );
+ return await fetchWithCache(
+ `owners:${owner}/${repo}`,
+ async ({ headers }) => {
+ return github.rest.repos.getContent({
+ owner,
+ repo,
+ path,
+ headers: {
+ Accept: "application/vnd.github.raw+json",
+ ...headers,
+ },
+ });
+ },
+ core,
+ );
+ } catch (error) {
+ core.warning(
+ `[repo: ${owner}/${repo}]: Failed to fetch CODEOWNERS file at ${path}: ${error.message}`,
+ );
+ }
+ }
+
+ core.error(
+ `[repo: ${owner}/${repo}]: CODEOWNERS file not found in any of the expected locations.`,
+ );
+ return null;
+}
+
+async function getAllCodeownersFiles(github, owner, repos, core) {
+ core.startGroup(`Fetching CODEOWNERS files for ${repos.length} repositories`);
+ const files = [];
+ for (const repo of repos) {
+ const data = await getCodeownersFile(github, owner, repo.name, core);
+ if (!data) {
+ continue;
+ }
+ files.push({
+ repo: repo.name,
+ content: data,
+ });
+ }
+ core.endGroup();
+ return files;
+}
+
+function removeNulls(obj) {
+ return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));
+}
diff --git a/.github/scripts/maintainers/index.js b/.github/scripts/maintainers/index.js
new file mode 100644
index 000000000..be32d8da5
--- /dev/null
+++ b/.github/scripts/maintainers/index.js
@@ -0,0 +1,190 @@
+const yaml = require("js-yaml");
+const fs = require("fs");
+const { saveCache, loadCache, printAPICallsStats } = require("./cache");
+const { summarizeChanges } = require("./summary");
+const {
+ getAllCodeownersFiles,
+ getGitHubProfile,
+ getRepositories,
+} = require("./gh_calls");
+
+module.exports = async ({ github, context, core }) => {
+ try {
+ await run(github, context, core);
+ } catch (error) {
+ console.log(error);
+ core.setFailed(`An error occurred: ${error}`);
+ }
+};
+
+const config = {
+ ghToken: process.env.GH_TOKEN,
+ ignoredRepos: getCommaSeparatedInputList(process.env.IGNORED_REPOSITORIES),
+ ignoredUsers: getCommaSeparatedInputList(process.env.IGNORED_USERS),
+ maintainersFilePath: process.env.MAINTAINERS_FILE_PATH,
+};
+
+function getCommaSeparatedInputList(list) {
+ return (
+ list
+ ?.split(",")
+ .map((item) => item.trim())
+ .filter((item) => item !== "") ?? []
+ );
+}
+
+function splitByWhitespace(line) {
+ return line.trim().split(/\s+/);
+}
+
+function extractGitHubUsernames(codeownersContent, core) {
+ if (!codeownersContent) return [];
+
+ const uniqueOwners = new Set();
+
+ for (const line of codeownersContent.split("\n")) {
+ // split by '#' to process comments separately
+ const [ownersLine, comment = ""] = line.split("#");
+
+ // 1. Check AsyncAPI custom owners
+ const triagers = comment.split(/docTriagers:|codeTriagers:/)[1]
+ if (triagers) {
+ const owners = splitByWhitespace(triagers)
+ owners.forEach(owner => uniqueOwners.add(owner))
+ }
+
+ // 2. Check GitHub native codeowners
+ const owners = splitByWhitespace(ownersLine);
+
+ // the 1st element is the file location, we don't need it, so we start with 2nd item
+ for (const owner of owners.slice(1)) {
+ if (!owner.startsWith("@") || owner.includes("/")) {
+ core.warning(`Skipping '${owner}' as emails and teams are not supported yet`);
+ continue;
+ }
+ uniqueOwners.add(owner.slice(1)); // remove the '@'
+ }
+ }
+
+ return uniqueOwners;
+}
+
+async function collectCurrentMaintainers(codeownersFiles, github, core) {
+ core.startGroup(`Fetching GitHub profile information for each codeowner`);
+
+ const currentMaintainers = {};
+ for (const codeowners of codeownersFiles) {
+ const owners = extractGitHubUsernames(codeowners.content, core);
+
+ for (const owner of owners) {
+ if (config.ignoredUsers.includes(owner)) {
+ core.debug(
+ `[repo: ${codeowners.repo}]: The user '${owner}' is on the ignore list. Skipping...`,
+ );
+ continue;
+ }
+ const key = owner.toLowerCase();
+ if (!currentMaintainers[key]) {
+ // Fetching GitHub profile is useful to ensure that all maintainers are valid (e.g., their GitHub accounts haven't been deleted).
+ const profile = await getGitHubProfile(github, owner, core);
+ if (!profile) {
+ core.warning(
+ `[repo: ${codeowners.repo}]: GitHub profile not found for ${owner}.`,
+ );
+ continue;
+ }
+
+ currentMaintainers[key] = { ...profile, repos: [] };
+ }
+
+ currentMaintainers[key].repos.push(codeowners.repo);
+ }
+ }
+
+ core.endGroup();
+ return currentMaintainers;
+}
+
+function refreshPreviousMaintainers(
+ previousMaintainers,
+ currentMaintainers,
+ core,
+) {
+ core.startGroup(`Refreshing previous maintainers list`);
+
+ const updatedMaintainers = [];
+
+ // 1. Iterate over the list of previous maintainers to:
+ // - Remove any maintainers who are not listed in any current CODEOWNERS files.
+ // - Update the repos list, ensuring that other properties (e.g., 'linkedin', 'slack', etc.) remain unchanged.
+ for (const previousEntry of previousMaintainers) {
+ const key = previousEntry.github.toLowerCase();
+ const currentMaintainer = currentMaintainers[key];
+ if (!currentMaintainer) {
+ core.info(
+ `The previous ${previousEntry.github} maintainer was not found in any CODEOWNERS file. Removing...`,
+ );
+ continue;
+ }
+ delete currentMaintainers[key];
+
+ updatedMaintainers.push({
+ ...previousEntry,
+ repos: currentMaintainer.repos,
+ githubID: currentMaintainer.githubID,
+ });
+ }
+
+ // 2. Append new codeowners who are not present in the previous Maintainers file.
+ const newMaintainers = Object.values(currentMaintainers);
+ updatedMaintainers.push(...newMaintainers);
+
+ core.endGroup();
+ return updatedMaintainers;
+}
+
+async function run(github, context, core) {
+ if (!config.maintainersFilePath) {
+ core.setFailed("The MAINTAINERS_FILE_PATH is not defined");
+ return;
+ }
+ loadCache(core);
+
+ const repos = await getRepositories(
+ github,
+ context.repo.owner,
+ config.ignoredRepos,
+ core,
+ );
+ const codeownersFiles = await getAllCodeownersFiles(
+ github,
+ context.repo.owner,
+ repos,
+ core,
+ );
+
+ const previousMaintainers = yaml.load(
+ fs.readFileSync(config.maintainersFilePath, "utf8"),
+ );
+
+ // 1. Collect new maintainers from all current CODEOWNERS files found across all repositories.
+ const currentMaintainers = await collectCurrentMaintainers(
+ codeownersFiles,
+ github,
+ core,
+ );
+
+ // 2. Refresh the repository list for existing maintainers and add any new maintainers to the list.
+ const refreshedMaintainers = refreshPreviousMaintainers(
+ previousMaintainers,
+ currentMaintainers,
+ core,
+ );
+
+ fs.writeFileSync(config.maintainersFilePath, yaml.dump(refreshedMaintainers));
+
+ printAPICallsStats(core);
+
+ await summarizeChanges(previousMaintainers, refreshedMaintainers, core);
+ saveCache();
+}
diff --git a/.github/scripts/maintainers/summary.js b/.github/scripts/maintainers/summary.js
new file mode 100644
index 000000000..e07d03fd4
--- /dev/null
+++ b/.github/scripts/maintainers/summary.js
@@ -0,0 +1,99 @@
+module.exports = { summarizeChanges };
+
+async function summarizeChanges(oldMaintainers, newMaintainers, core) {
+ const outOfSync = [];
+ const noLongerActive = [];
+
+ const newMaintainersByGitHubName = new Map();
+ for (const newMaintainer of newMaintainers) {
+ newMaintainersByGitHubName.set(newMaintainer.github, newMaintainer);
+ }
+
+ for (const oldEntry of oldMaintainers) {
+ const newEntry = newMaintainersByGitHubName.get(oldEntry.github);
+
+ if (!newEntry) {
+ noLongerActive.push([oldEntry.github, repositoriesLinks(oldEntry.repos)]);
+ continue;
+ }
+
+ const { newOwnedRepos, noLongerOwnedRepos } = compareRepos(
+ oldEntry.repos,
+ newEntry.repos,
+ );
+
+ if (newOwnedRepos.length > 0 || noLongerOwnedRepos.length > 0) {
+ outOfSync.push([
+ profileLink(oldEntry.github),
+ repositoriesLinks(newOwnedRepos),
+ repositoriesLinks(noLongerOwnedRepos),
+ ]);
+ }
+ }
+
+ if (outOfSync.length > 0) {
+ core.summary.addHeading("⚠️ Out of Sync Maintainers", "2");
+ core.summary.addTable([
+ [
+ { data: "Name", header: true },
+ { data: "Newly added to CODEOWNERS", header: true },
+ { data: "No longer in CODEOWNERS", header: true },
+ ],
+ ...outOfSync,
+ ]);
+ core.summary.addBreak();
+ }
+
+ if (noLongerActive.length > 0) {
+ core.summary.addHeading(
+ "👻 Inactive Maintainers (not listed in any repositories)",
+ "2",
+ );
+
+ core.summary.addTable([
+ [
+ { data: "Name", header: true },
+ { data: "Previously claimed ownership in repos", header: true },
+ ],
+ ...noLongerActive,
+ ]);
+
+ core.summary.addBreak();
+ }
+
+ await core.summary.write({ overwrite: true });
+}
+
+function compareRepos(oldRepos, newRepos) {
+ const newOwnedRepositories = [];
+ const noLongerOwnedRepositories = [];
+
+ for (const repo of newRepos) {
+ if (!oldRepos.includes(repo)) {
+ newOwnedRepositories.push(repo);
+ }
+ }
+
+ for (const repo of oldRepos) {
+ if (!newRepos.includes(repo)) {
+ noLongerOwnedRepositories.push(repo);
+ }
+ }
+
+ return {
+ newOwnedRepos: newOwnedRepositories,
+ noLongerOwnedRepos: noLongerOwnedRepositories,
+ };
+}
+
+function repositoriesLinks(repos) {
+ return repos
+ .map((repo) => {
+ return `${repo}`;
+ })
+ .join(", ");
+}
+
+function profileLink(login) {
+ return `${login}
`;
+}
diff --git a/.github/workflows/update-maintainers.yaml b/.github/workflows/update-maintainers.yaml
new file mode 100644
index 000000000..858eb02aa
--- /dev/null
+++ b/.github/workflows/update-maintainers.yaml
@@ -0,0 +1,130 @@
+# This action updates the `MAINTAINERS.yaml` file based on `CODEOWNERS` files in all organization repositories.
+# It is triggered when a `CODEOWNERS` file is changed; the related repository triggers this workflow by emitting the `trigger-maintainers-update` event.
+# It can also be triggered manually.
+
+name: Update MAINTAINERS.yaml file
+
+on:
+ push:
+ branches: [ master ]
+ paths:
+ - 'CODEOWNERS'
+ - '.github/scripts/maintainers/**'
+ - '.github/workflows/update-maintainers.yaml'
+
+ schedule:
+ - cron: "0 10 * * SUN" # Runs at 10:00 AM UTC every Sunday.
+
+ workflow_dispatch:
+
+ repository_dispatch:
+ types: [ trigger-maintainers-update ]
+
+concurrency:
+ group: ${{ github.workflow }}
+ cancel-in-progress: false
+
+env:
+ IGNORED_REPOSITORIES: "shape-up-process"
+ IGNORED_USERS: "asyncapi-bot-eve"
+
+ BRANCH_NAME: "bot/update-maintainers-${{ github.run_id }}"
+ PR_TITLE: "docs(maintainers): update MAINTAINERS.yaml file with the latest CODEOWNERS changes"
+
+jobs:
+ update-maintainers:
+ name: Update MAINTAINERS.yaml based on CODEOWNERS files in all organization repositories
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ # If an action pushes code using the repository’s GITHUB_TOKEN, a pull request workflow will not run.
+ token: ${{ secrets.GH_TOKEN }}
+
+ - name: Wait for active pull requests to be merged
+ env:
+ GH_TOKEN: ${{ github.token }}
+ TIMEOUT: 300 # Timeout in seconds
+ INTERVAL: 5 # Check interval in seconds
+ run: |
+ check_active_prs() {
+ ACTIVE_PULL_REQUESTS=$(gh -R $GITHUB_REPOSITORY pr list --search "is:pr ${PR_TITLE} in:title" --json id)
+ if [ "$ACTIVE_PULL_REQUESTS" == "[]" ]; then
+ return 1 # No active PRs
+ else
+ return 0 # Active PRs found
+ fi
+ }
+
+ # Loop with timeout
+ elapsed_time=0
+ while [ $elapsed_time -lt $TIMEOUT ]; do
+ if check_active_prs; then
+ echo "There is an active pull request. Waiting for it to be merged..."
+ else
+ echo "There is no active pull request. Proceeding with updating MAINTAINERS file."
+ git pull
+ exit 0
+ fi
+
+ sleep $INTERVAL
+ elapsed_time=$((elapsed_time + INTERVAL))
+ done
+
+ echo "Timeout reached. Proceeding with updating MAINTAINERS.yaml file with active pull request(s) present. It may result in merge conflict."
+ exit 0
+
+ - name: Restore cached GitHub API calls
+ uses: actions/cache/restore@v4
+ with:
+ path: ./.github/scripts/maintainers/github.api.cache.json
+ key: github-api-cache
+ restore-keys: |
+ github-api-cache-
+
+ - name: Installing Module
+ shell: bash
+ run: npm install js-yaml@4 --no-save
+
+ - name: Run script updating MAINTAINERS.yaml
+ uses: actions/github-script@v7
+ env:
+ GH_TOKEN: ${{ github.token }}
+ MAINTAINERS_FILE_PATH: "${{ github.workspace }}/MAINTAINERS.yaml"
+ with:
+ script: |
+ const script = require('./.github/scripts/maintainers/index.js')
+ await script({github, context, core})
+
+ - name: Save cached GitHub API calls
+ uses: actions/cache/save@v4
+ with:
+ path: ./.github/scripts/maintainers/github.api.cache.json
+ # re-evaluate the key, so we update cache when file changes
+ key: github-api-cache-${{ hashfiles('./.github/scripts/maintainers/github.api.cache.json') }}
+
+ - name: Create PR with latest changes
+ uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # https://github.com/peter-evans/create-pull-request/releases/tag/v6.1.0
+ with:
+ token: ${{ secrets.GH_TOKEN }}
+ commit-message: ${{ env.PR_TITLE }}
+ committer: asyncapi-bot
+ author: asyncapi-bot
+ title: ${{ env.PR_TITLE }}
+ branch: ${{ env.BRANCH_NAME }}
+ body: |
+ **Description**
+ - Update MAINTAINERS.yaml based on CODEOWNERS files across all repositories in the organization.
+
+ For details on why a maintainer was removed or changed, refer to the [Job summary page](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).
+
+ - name: Report workflow run status to Slack
+ uses: rtCamp/action-slack-notify@4e5fb42d249be6a45a298f3c9543b111b02f7907 # https://github.com/rtCamp/action-slack-notify/releases/tag/v2.3.0
+ if: failure()
+ env:
+ SLACK_WEBHOOK: ${{secrets.SLACK_CI_FAIL_NOTIFY}}
+ SLACK_TITLE: 🚨 Update MAINTAINERS.yaml file Workflow failed 🚨
+ SLACK_MESSAGE: Failed to auto update MAINTAINERS.yaml file.
+ MSG_MINIMAL: true
diff --git a/MAINTAINERS.yaml b/MAINTAINERS.yaml
index 29ad9ddb3..e9c443ce7 100644
--- a/MAINTAINERS.yaml
+++ b/MAINTAINERS.yaml
@@ -7,6 +7,9 @@
isTscMember: true
repos:
- website
+ - conference-website
+ - brand
+ githubID: 105395613
- name: Aayush Sahu
github: aayushmau5
linkedin: aayushmau5
@@ -16,6 +19,7 @@
isTscMember: true
repos:
- diff
+ githubID: 54525741
- name: Abir Pal
linkedin: imabp
slack: U01S8EQ9LQ2
@@ -25,6 +29,7 @@
isTscMember: true
repos:
- problem
+ githubID: 53480076
- name: Akshat Nema
github: akshatnema
linkedin: akshat-nema
@@ -34,6 +39,7 @@
isTscMember: true
repos:
- website
+ githubID: 76521428
- name: Ansh Goyal
github: anshgoyalevil
linkedin: thisisanshg
@@ -43,6 +49,7 @@
isTscMember: true
repos:
- website
+ githubID: 94157520
- name: Anand Sunderraman
github: anandsunderraman
linkedin: anand-sunderraman-a6b7a131
@@ -51,6 +58,7 @@
isTscMember: true
repos:
- go-watermill-template
+ githubID: 4500774
- name: Ashish Padhy
github: Shurtu-gal
linkedin: ashish-padhy3023
@@ -60,6 +68,8 @@
isTscMember: true
repos:
- github-action-for-cli
+ - cli
+ githubID: 100484401
- name: Cameron Rushton
github: CameronRushton
slack: U01DVKKAV5K
@@ -67,9 +77,11 @@
company: Solace
isTscMember: true
repos:
+ - spec-json-schemas
+ - bindings
- java-spring-cloud-stream-template
- python-paho-template
- - bindings
+ githubID: 32455969
- name: Dale Lane
github: dalelane
linkedin: dalelane
@@ -79,9 +91,12 @@
isTscMember: true
company: IBM
repos:
- - avro-schema-parser
+ - spec
+ - spec-json-schemas
- bindings
+ - avro-schema-parser
- java-template
+ githubID: 1444788
- name: Emiliano Zublena
github: emilianozublena
linkedin: emilianozublena
@@ -89,7 +104,8 @@
availableForHire: false
isTscMember: false
repos:
- - asyncapi-php-template
+ - php-template
+ githubID: 466639
- name: Fran Méndez
github: fmvilas
slack: U34F2JRRS
@@ -97,16 +113,21 @@
linkedin: fmvilas
isTscMember: true
repos:
- - raml-dt-schema-parser
- - avro-schema-parser
- - openapi-schema-parser
- - asyncapi-react
- - glee
- - nodejs-ws-template
- - parser-js
- spec
- spec-json-schemas
+ - asyncapi-react
+ - extensions-catalog
+ - converter-js
- bindings
+ - enterprise-patterns
+ - raml-dt-schema-parser
+ - openapi-schema-parser
+ - html-template
+ - markdown-template
+ - nodejs-ws-template
+ - generator-hooks
+ - brand
+ githubID: 242119
- name: Gerald Loeffler
github: GeraldLoeffler
linkedin: geraldloeffler
@@ -114,7 +135,9 @@
availableForHire: false
isTscMember: false
repos:
+ - spec-json-schemas
- bindings
+ githubID: 1985716
- name: Jonas Lagoni
github: jonaslagoni
linkedin: jonaslagoni
@@ -123,14 +146,18 @@
company: Postman
isTscMember: true
repos:
- - dotnet-nats-template
+ - spec-json-schemas
+ - generator
+ - parser-js
+ - converter-js
- ts-nats-template
+ - dotnet-nats-template
- generator-react-sdk
- - generator
- modelina
- - parser-js
- - parser-api
- simulator
+ - parser-api
+ - EDAVisualiser
+ githubID: 13396189
- name: Khuda Dad Nomani
github: KhudaDad414
twitter: KhudaDadNomani
@@ -140,10 +167,12 @@
company: Postman
isTscMember: true
repos:
- - bindings
- - glee
+ - spec-json-schemas
+ - studio
- .github
- optimizer
+ - glee
+ githubID: 32505158
- name: Laurent Broudoux
github: lbroudoux
twitter: lbroudoux
@@ -153,7 +182,9 @@
company: Postman
isTscMember: true
repos:
+ - spec-json-schemas
- bindings
+ githubID: 1538635
- name: Ludovic Dussart
github: M3lkior
linkedin: ludovic-dussart-846a8063
@@ -164,6 +195,7 @@
isTscMember: true
repos:
- avro-schema-parser
+ githubID: 5501911
- name: Lukasz Gornicki
github: derberg
linkedin: lukasz-gornicki-a621914
@@ -173,17 +205,30 @@
company: Postman
isTscMember: true
repos:
- - diff
- - generator-filters
- - generator-hooks
- - github-action-for-generator
+ - spec
+ - website
+ - spec-json-schemas
- generator
+ - asyncapi-react
+ - extensions-catalog
+ - bindings
+ - enterprise-patterns
+ - html-template
+ - markdown-template
- nodejs-template
- nodejs-ws-template
- - spec
- - spec-json-schemas
+ - java-spring-template
+ - github-action-for-cli
+ - .github
+ - jasyncapi
+ - generator-hooks
+ - vs-asyncapi-preview
- template-for-generator-templates
- - website
+ - community
+ - diff
+ - chatbot
+ - infra
+ githubID: 6995927
- name: Maciej Urbańczyk
github: magicmatatjahu
availableForHire: false
@@ -192,18 +237,29 @@
company: Travelping GmbH
isTscMember: true
repos:
+ - website
+ - generator
- asyncapi-react
+ - parser-go
+ - parser-js
+ - converter-js
- converter-go
- - generator-react-sdk
- - generator
+ - studio
- html-template
- markdown-template
+ - github-action-for-cli
+ - ts-nats-template
+ - dotnet-nats-template
+ - template-for-generator-templates
+ - generator-react-sdk
- modelina
- - parser-js
- - parser-go
- - server-api
- template-for-go-projects
- - website
+ - diff
+ - chatbot
+ - server-api
+ - EDAVisualiser
+ - problem
+ githubID: 20404945
- name: Azeez Elegbede
linkedin: acebuild
github: AceTheCreator
@@ -213,26 +269,20 @@
availableForHire: false
isTscMember: true
repos:
+ - conference-website
- chatbot
+ githubID: 40604284
- name: Michael Davis
github: damaru-inc
availableForHire: false
slack: UH3B166TD
isTscMember: false
repos:
+ - spec-json-schemas
+ - bindings
- java-spring-cloud-stream-template
- python-paho-template
- - bindings
-- name: Missy Turco
- github: mcturco
- twitter: missyturco
- slack: U02JVEQ6S9W
- linkedin: missy-turco-a476a6126
- availableForHire: false
- company: Postman
- isTscMember: false
- repos:
- - brand
+ githubID: 3926925
- name: Nektarios Fifes
github: NektariosFifes
linkedin: nektarios-fifes-372740220
@@ -241,6 +291,7 @@
isTscMember: true
repos:
- simulator
+ githubID: 61620751
- name: Pavel Bodiachevskii
github: Pakisan
slack: U0132LQU8C9
@@ -248,7 +299,11 @@
availableForHire: false
isTscMember: true
repos:
+ - spec-json-schemas
+ - tck
- jasyncapi
+ - jasyncapi-idea-plugin
+ githubID: 3388414
- name: Philip Schlesinger
github: theschles
slack: U054UUYBNLF
@@ -257,6 +312,7 @@
isTscMember: true
repos:
- jasyncapi-idea-plugin
+ githubID: 901430
- name: Prince Rajpoot
github: princerajpoot20
linkedin: princerajpoot
@@ -266,6 +322,7 @@
isTscMember: true
repos:
- studio
+ githubID: 44585452
- name: Richard Coppen
github: rcoppen
linkedin: richard-coppen
@@ -274,7 +331,9 @@
company: IBM
isTscMember: true
repos:
+ - spec-json-schemas
- bindings
+ githubID: 30902631
- name: Samir AMZANI
github: Amzani
slack: U01N6AW5V5G
@@ -285,6 +344,8 @@
isTscMember: true
repos:
- studio
+ - cli
+ githubID: 554438
- name: Sergio Moya
github: smoya
linkedin: smoya
@@ -296,17 +357,19 @@
repos:
- spec
- spec-json-schemas
- - bindings
- - parser-api
- - parser-js
- - avro-schema-parser
- - openapi-schema-parser
- - raml-dt-schema-parser
- - server-api
- parser-go
+ - parser-js
- converter-go
+ - bindings
+ - raml-dt-schema-parser
+ - openapi-schema-parser
+ - avro-schema-parser
- go-watermill-template
- template-for-go-projects
+ - parser-api
+ - server-api
+ - infra
+ githubID: 1083296
- name: Souvik De
github: Souvikns
slack: U01SGCZMJKW
@@ -317,8 +380,9 @@
isTscMember: true
repos:
- cli
- - bundler
- glee
+ - bundler
+ githubID: 41781438
- name: Quetzalli Writes
github: quetzalliwrites
twitter: QuetzalliWrites
@@ -329,8 +393,7 @@
isTscMember: true
repos:
- website
- - training
- - community
+ githubID: 19964402
- name: David Pereira
github: BOLT04
twitter: BOLT2938
@@ -341,6 +404,7 @@
isTscMember: true
repos:
- server-api
+ githubID: 18630253
- name: Daniel Raper
github: dan-r
slack: U02FP8WBFQE
@@ -349,6 +413,7 @@
isTscMember: true
repos:
- java-template
+ githubID: 1384852
- name: Kieran Murphy
github: KieranM1999
linkedin: kieran-murphy-175b0412b
@@ -358,6 +423,7 @@
isTscMember: false
repos:
- java-template
+ githubID: 45017928
- name: Tom Jefferson
github: JEFFLUFC
linkedin: t-jefferson
@@ -367,6 +433,7 @@
isTscMember: false
repos:
- java-template
+ githubID: 54025356
- name: Lewis Relph
github: lewis-relph
availableForHire: false
@@ -375,6 +442,7 @@
isTscMember: false
repos:
- java-template
+ githubID: 91530893
- name: Semen Tenishchev
github: Tenischev
linkedin: semen-tenishchev
@@ -383,6 +451,7 @@
isTscMember: true
repos:
- java-spring-template
+ githubID: 4137916
- name: Samridhi Agrawal
github: Samridhi-98
slack: U02T2MY9W5T
@@ -392,16 +461,7 @@
isTscMember: true
repos:
- modelina
-- name: Debajyoti Halder
- github: ron-debajyoti
- twitter: rondebajyoti
- slack: U02UK9RUPGQ
- linkedin: rondebajyoti
- availableForHire: false
- company: Narvar
- isTscMember: false
- repos:
- - modelina
+ githubID: 54466041
- name: Ivan Garcia Sainz-Aja
github: ivangsa
linkedin: ivangarciasainzaja
@@ -411,6 +471,7 @@
isTscMember: true
repos:
- vs-asyncapi-preview
+ githubID: 1246876
- name: Florence Njeri
github: Florence-Njeri
linkedin: florencenjeri
@@ -420,6 +481,7 @@
isTscMember: true
repos:
- generator
+ githubID: 40742916
- name: Jeremy Whitlock
github: whitlockjc
linkedin: whitlockjc
@@ -429,7 +491,9 @@
company: Google
isTscMember: true
repos:
+ - spec-json-schemas
- bindings
+ githubID: 98899
- name: Vladimír Gorej
github: char0n
linkedin: vladimirgorej
@@ -439,18 +503,22 @@
company: SmartBear
isTscMember: false
repos:
- - bindings
- spec
- spec-json-schemas
+ - bindings
+ githubID: 193286
- name: Alexander Wichmann
- github: VisualBean
+ github: VisualBean
linkedin: alexcarlsen
slack: U04C58GB8TF
availableForHire: false
company: The LEGO Group
isTscMember: true
repos:
+ - spec-json-schemas
- bindings
+ - saunter
+ githubID: 5294032
- name: Kenneth Aasan
github: kennethaasan
slack: U037S2HK4TS
@@ -460,6 +528,7 @@
isTscMember: true
repos:
- modelina
+ githubID: 1437394
- name: Heiko Henning
github: GreenRover
slack: U03AC4G51H8
@@ -467,7 +536,11 @@
company: mtrail GmbH
isTscMember: true
repos:
+ - spec
+ - spec-json-schemas
+ - bindings
- protobuf-schema-parser
+ githubID: 512850
- name: connil
github: connil
slack: U03A51H8
@@ -476,6 +549,7 @@
isTscMember: false
repos:
- dotnet-rabbitmq-template
+ githubID: 6583798
- name: mr-nuno
github: mr-nuno
slack: U03A5145
@@ -484,6 +558,7 @@
isTscMember: false
repos:
- dotnet-rabbitmq-template
+ githubID: 1067841
- name: Thulisile Sibanda
github: thulieblack
linkedin: v-thulisile-sibanda
@@ -494,7 +569,9 @@
isTscMember: true
repos:
- website
+ - conference-website
- community
+ githubID: 66913810
- name: Ashmit JaiSarita Gupta
github: devilkiller-ag
linkedin: jaisarita
@@ -504,6 +581,7 @@
isTscMember: true
repos:
- modelina
+ githubID: 43639341
- name: Sambhav Gupta
github: sambhavgupta0705
linkedin: sambhavgupta0705
@@ -513,11 +591,162 @@
isTscMember: true
repos:
- website
+ githubID: 81870866
- name: Viacheslav Turovskyi
github: aeworxet
slack: U01G3U01SVC
availableForHire: false
isTscMember: false
repos:
- - bundler
- optimizer
+ - bundler
+ githubID: 16149591
+- name: Rohit
+ github: TRohit20
+ twitter: TRRohit20
+ isTscMember: false
+ repos:
+ - website
+ githubID: 108233235
+- name: 'Bhaswati Roy '
+ github: BhaswatiRoy
+ twitter: swiftiebhaswati
+ isTscMember: false
+ repos:
+ - website
+ githubID: 78029145
+- name: 'Vaishnavi '
+ github: VaishnaviNandakumar
+ isTscMember: false
+ repos:
+ - website
+ githubID: 41518119
+- name: Joy Almeida
+ github: J0SAL
+ twitter: _j0sal
+ isTscMember: false
+ repos:
+ - website
+ githubID: 52382282
+- name: Mihael Bosnjak
+ github: mboss37
+ isTscMember: false
+ repos:
+ - spec-json-schemas
+ - bindings
+ githubID: 29606687
+- name: Steve Head
+ github: SrfHead
+ isTscMember: false
+ repos:
+ - spec-json-schemas
+ - bindings
+ githubID: 13767299
+- name: Dec Kolakowski
+ github: dpwdec
+ isTscMember: false
+ repos:
+ - spec-json-schemas
+ - bindings
+ githubID: 51292634
+- name: Ian Cooper
+ github: iancooper
+ twitter: ICooper
+ isTscMember: false
+ repos:
+ - spec-json-schemas
+ - bindings
+ githubID: 45537
+- name: Michael Wildman
+ github: m-wild
+ isTscMember: false
+ repos:
+ - saunter
+ githubID: 3260812
+- name: yurvon-screamo
+ github: yurvon-screamo
+ isTscMember: false
+ repos:
+ - saunter
+ githubID: 109030262
+- name: Jonathan Stoikovitch
+ github: jstoiko
+ twitter: jstoiko
+ isTscMember: false
+ repos:
+ - raml-dt-schema-parser
+ githubID: 9660342
+- name: Rishi
+ github: kaushik-rishi
+ twitter: KaushikRishi07
+ isTscMember: false
+ repos:
+ - nodejs-template
+ githubID: 52498617
+- name: Akshit Gupta
+ github: akkshitgupta
+ twitter: akkshitgupta
+ availableForHire: true
+ isTscMember: false
+ repos:
+ - modelina
+ githubID: 96991785
+- name: Leigh Johnson
+ github: leigh-johnson
+ twitter: grepLeigh
+ isTscMember: false
+ repos:
+ - modelina
+ githubID: 2601819
+- name: Zbigniew Malcherczyk
+ github: ferror
+ isTscMember: false
+ repos:
+ - modelina
+ githubID: 17534504
+- name: artur-ciocanu
+ github: artur-ciocanu
+ isTscMember: false
+ repos:
+ - modelina
+ githubID: 743192
+- name: Vinit Shahdeo
+ github: vinitshahdeo
+ twitter: Vinit_Shahdeo
+ availableForHire: true
+ isTscMember: false
+ repos:
+ - diff
+ githubID: 20594326
+- name: Anubhav Vats
+ github: onbit-uchenik
+ twitter: postmanlabs
+ availableForHire: true
+ isTscMember: false
+ repos:
+ - diff
+ githubID: 46771418
+- name: Akshaya Gurlhosur
+ github: AGurlhosur
+ isTscMember: false
+ repos:
+ - java-template
+ githubID: 91530186
+- name: Philip Schlesinger @ Cryoport
+ github: philCryoport
+ isTscMember: false
+ repos:
+ - jasyncapi-idea-plugin
+ githubID: 28901899
+- name: nathanaelweber
+ github: nathanaelweber
+ isTscMember: false
+ repos:
+ - protobuf-schema-parser
+ githubID: 40006685
+- name: Barbanio González
+ github: Barbanio
+ isTscMember: false
+ repos:
+ - learning-paths
+ githubID: 77982319
diff --git a/tweets/recurring-slack-link/2024-08-24.tweet b/tweets/recurring-slack-link/2024-08-24.tweet
new file mode 100644
index 000000000..0bd3e8865
--- /dev/null
+++ b/tweets/recurring-slack-link/2024-08-24.tweet
@@ -0,0 +1,7 @@
+✨ Did you know #AsyncAPI is on Slack? ✨
+
+Join our Slack workspace to chat with anyone from our Open-Source community!
+
+🔗 asyncapi.com/slack-invite
+
+Ask for help and help others too. 💪🏿💪🏽🦾
\ No newline at end of file