diff --git a/.all-contributorsrc b/.all-contributorsrc index 9423d1e4b..c987b201a 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -448,6 +448,17 @@ "contributions": [ "doc" ] + }, + { + "login": "gvensan", + "name": "Giri Venkatesan", + "avatar_url": "https://avatars.githubusercontent.com/u/4477169?v=4", + "profile": "https://github.com/gvensan", + "contributions": [ + "talk", + "blog", + "promotion" + ] } ], "commitConvention": "angular", diff --git a/.github/actions/verifyTSCMember/action.yml b/.github/actions/verifyTSCMember/action.yml new file mode 100644 index 000000000..261f34909 --- /dev/null +++ b/.github/actions/verifyTSCMember/action.yml @@ -0,0 +1,46 @@ +name: Verify Member +outputs: + isTSCMember: + description: 'Check whether the person is TSCMember or not' + value: ${{steps.verify_member.outputs.isTSCMember}} +inputs: + authorName: + description: 'Name of the commentor' + required: true + +runs: + using: "composite" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install the dependencies + run: npm install js-yaml@4.1.0 + shell: bash + + - name: Verify TSC Member + id: verify_member + uses: actions/github-script@v6 + with: + script: | + const yaml = require('js-yaml'); + const fs = require('fs'); + const commenterName = '${{ inputs.authorName }}'; + let isTSCMember = false; + try { + // Load YAML file + const data = yaml.load(fs.readFileSync('MAINTAINERS.yaml', 'utf8')); + + // Filter persons who are TSC members and whose GitHub username matches commenterName + const isTscMember = data.find(person => { + return (person.isTscMember === true || person.isTscMember === "true") && person.github === commenterName; + }); + // Check if a TSC member was found + if (isTscMember) { + isTSCMember = true; + } + + core.setOutput('isTSCMember', isTSCMember); + } catch (e) { + console.log(e); + } \ No newline at end of file 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/scripts/vote_tracker.js b/.github/scripts/vote_tracker.js new file mode 100644 index 000000000..9666145cb --- /dev/null +++ b/.github/scripts/vote_tracker.js @@ -0,0 +1,297 @@ +const yaml = require('js-yaml'); +const { readFile, writeFile } = require('fs').promises; +const path = require("path") +module.exports = async ({ github, context, botCommentURL}) => { + try { + let message, eventNumber, eventTitle, orgName, repoName; + if (botCommentURL) { + const voteCommentContext = await fetchCommentInformation(); + message = voteCommentContext.messageBody + eventNumber = voteCommentContext.eventNumber + eventTitle = voteCommentContext.eventTitle + orgName = voteCommentContext.orgName + repoName = voteCommentContext.repoName + } else { + // Extract necessary details from the context when triggered by issue_comment + message = context.payload.comment.body; + eventNumber = context.issue.number; + eventTitle = context.payload.issue.title; + orgName = context.repo.owner; + repoName = context.repo.repo; + } + + // Path to the vote tracking file + const voteTrackingFile = path.join('voteTrackingFile.json'); + + // Parse the vote-closed comment created by git-vote[bot] + const votingRows = await parseVoteClosedComment(); + + // Example table vote comment that is parsed here https://github.com/asyncapi/community/issues/1227#issuecomment-2167463252 + const latestVotes = votingRows.map(row => { + //skipping first element as parsing is based on split, so table where column starts with | will have first element of created array empty + const [, user, vote, timestamp] = row.split('|').map(col => col.trim()); + return { user: user.replace('@', ''), vote, timestamp, isVotedInLast3Months: true }; + }); + + let maintainerInformation; + try { + const maintainerInfo = await readFile('MAINTAINERS.yaml', 'utf8'); + maintainerInformation = yaml.load(maintainerInfo); + } catch (readError) { + console.error('Error reading MAINTAINERS.yaml:', readError); + throw readError; + } + + // Update the TSC Members + const voteDetails = await updateVoteTrackingFile(); + + const updatedVoteDetails = []; + + // Process each vote detail to update voting information + voteDetails.forEach(voteInfo => { + const userVote = latestVotes.find(vote => vote.user.toLowerCase() === voteInfo.name.toLowerCase()); + let currentTime; + if (userVote && userVote.timestamp) { + currentTime = userVote.timestamp.toString().split(" ")[0]; + } + const userInfo = latestVotes.find(vote => vote.user.toLowerCase() === voteInfo.name.toLowerCase()); + const voteChoice = userInfo ? userInfo.vote : "Not participated"; + voteInfo.lastVoteClosedTime = new Date().toISOString().split('T')[0]; + + if (userInfo) { + voteInfo.isVotedInLast3Months = true; + voteInfo.lastParticipatedVoteTime = currentTime; + voteInfo[voteChoice === "In favor" ? 'agreeCount' : voteChoice === "Against" ? 'disagreeCount' : 'abstainCount']++; + } else { + voteInfo.notParticipatingCount++; + if (isVotingWithinLastThreeMonths(voteInfo)) { + voteInfo.isVotedInLast3Months = false; + } + } + + // Update vote information with the issue title and number + let updatedVoteInfo = {}; + Object.keys(voteInfo).forEach(key => { + if (key === 'name') { + updatedVoteInfo['name'] = voteInfo.name; + updatedVoteInfo[eventTitle + "$$" + eventNumber] = voteChoice; + } else { + updatedVoteInfo[key] = voteInfo[key]; + } + }); + updatedVoteDetails.push(updatedVoteInfo); + }); + + try { + await writeFile(voteTrackingFile, JSON.stringify(updatedVoteDetails, null, 2)); + } catch (writeError) { + console.error('Error writing to voteTrackingFile.json:', writeError); + throw writeError; + } + + const markdownTable = await jsonToMarkdownTable(updatedVoteDetails); + try { + await writeFile('TSC_VOTING_OVERVIEW.md', markdownTable); + console.log('Markdown table has been written to TSC_VOTING_OVERVIEW.md'); + } catch (writeError) { + console.error('Error writing to TSC_VOTING_OVERVIEW.md:', writeError); + throw writeError; + } + + async function jsonToMarkdownTable(data) { + if (!data || data.length === 0) { + console.error("Data is empty or undefined"); + return ''; + } + + const keys = Object.keys(data[0]).filter(key => key !== 'firstVoteClosedTime'); + + const titles = { + name: "GitHub user name", + lastParticipatedVoteTime: "Last time the TSC member participated in a vote", + hasVotedInLast3Months: "Flag indicating if TSC member voted in last 3 months. This information is calculated after each voting, and not basing on a schedule as there might be moments when there is no voting in place for 3 months and therefore no TSC member votes.", + lastVoteClosedTime: "Date when last vote was closed. It indicated when the last voting took place and marks the date when this tracking document was updated.", + agreeCount: "Number of times TSC member agreed in a vote.", + disagreeCount: "Number of times TSC member did not agree in a vote.", + abstainCount: "Number of times TSC member abstained from voting.", + notParticipatingCount: "Number of times TSC member did not participate in voting." + }; + + // Fill missing properties with default values and log the processing + data = data.map((obj, index) => { + const newObj = {}; + keys.forEach(key => { + newObj[key] = obj[key] !== undefined ? obj[key] : 'N/A'; + }); + return newObj; + }); + + let markdownTable = '\n'; + markdownTable += '| ' + keys.map(key => { + if (key.includes('$$')) { + const [title, number] = key.split('$$'); + return `[${title}](https://github.com/${orgName}/${repoName}/issues/${number})`; + } + return `${key}`; + }).join(' | ') + ' |\n'; + + markdownTable += '| ' + keys.map(() => '---').join(' | ') + ' |\n'; + markdownTable += data.map(obj => '| ' + keys.map(key => { + if (key === 'name') return `[${obj[key]}](https://github.com/${obj[key]})`; + if (key.includes('$$')) { + const icons = { + "In favor": "👍", + "Against": "👎", + "Abstain": "👀", + "Not participated": "🔕" + }; + return `${icons[obj[key]] || obj[key]}`; + } + return obj[key]; + }).join(' | ') + ' |').join('\n'); + + return markdownTable; + } + + + // Parse the vote-closed comment created by git-vote[bot] + // No need to look for "Vote closed" as this is already validated by the workflow that runs this code + async function parseVoteClosedComment() { + const bindingVotesSectionMatch = message.match(/Binding votes \(\d+\)[\s\S]*?(?=(
|$))/); + const bindingVotesSection = bindingVotesSectionMatch ? bindingVotesSectionMatch[0] : ''; + return bindingVotesSection.match(/\| @\w+.*?\|.*?\|.*?\|/g) || []; + } + + // Check if voting duration is within the last three months + function isVotingWithinLastThreeMonths(voteInfo) { + const currentDate = new Date(); + let previousDate; + if (voteInfo.isVotedInLast3Months === "Member has not voted in all previous voting process.") { + previousDate = new Date(voteInfo.firstVoteClosedTime); + } else { + previousDate = new Date(voteDetails.lastVoteClosedTime); + } + const yearDiff = currentDate.getFullYear() - previousDate.getFullYear(); + const monthDiff = currentDate.getMonth() - previousDate.getMonth(); + const totalMonthsDiff = yearDiff * 12 + monthDiff; + + return totalMonthsDiff > 3; + } + + // Function to update the voteTrackingFile with updated TSC Members + async function updateVoteTrackingFile() { + const tscMembers = maintainerInformation.filter(entry => entry.isTscMember); + let voteDetails = []; + try { + voteDetails = JSON.parse(await readFile(voteTrackingFile, 'utf8')); + } catch (readError) { + console.error('Error reading voteTrackingFile.json:', readError); + throw readError; + } + let updatedVoteDetails = [...voteDetails] + const updatedTSCMembers = []; + const requiredKeys = ['name', 'lastParticipatedVoteTime', 'isVotedInLast3Months', 'lastVoteClosedTime', 'agreeCount', 'disagreeCount', 'abstainCount', 'notParticipatingCount']; + // Function to check if an object has all required keys + const isValidExampleMember = (member) => { + return requiredKeys.every(key => member.hasOwnProperty(key)); + }; + // Find the first valid example member + const validExampleMember = voteDetails.find(isValidExampleMember); + + if (validExampleMember) { + tscMembers.forEach(member => { + const existingMember = voteDetails.find(voteInfo => voteInfo.name.toLowerCase() === member.github.toLowerCase()); + if (!existingMember) { + // Create a new member by copying the structure of the valid example member + const newMember = {}; + + // Copy the keys from the valid example member to the new member with default values + Object.keys(validExampleMember).forEach(key => { + switch (key) { + case 'name': + newMember[key] = member.github; + break; + case 'lastParticipatedVoteTime': + newMember[key] = 'Member has not participated in all previous voting process.'; + break; + case 'isVotedInLast3Months': + newMember[key] = 'Member has not participated in all previous voting process.'; + break; + case 'lastVoteClosedTime': + newMember[key] = new Date().toISOString().split('T')[0]; + break; + case 'firstVoteClosedTime': + newMember[key] = validExampleMember['firstVoteClosedTime']; // This is used to determine when the first vote closed so that we can determine the duration between two votes easily + break; + case 'agreeCount': + case 'disagreeCount': + case 'abstainCount': + case 'notParticipatingCount': + newMember[key] = 0; + break; + default: + newMember[key] = "Not participated"; + } + }); + + updatedTSCMembers.push(newMember); + } + }); + } else { + console.log('No valid example member found in voteDetails.'); + } + + if (updatedTSCMembers.length > 0) { + try { + updatedVoteDetails.concat(...updatedTSCMembers) + await writeFile(voteTrackingFile, JSON.stringify(updatedVoteDetails, null, 2)); + } catch (writeError) { + console.error('Error wile writing file:' ,writeError) + } + } + return updatedVoteDetails + } + // Method to fetch information from the comment when workflow triggered manually + async function fetchCommentInformation() { + const urlParts = botCommentURL.split('/'); + const eventNumber = urlParts[urlParts.length - 1].split('#')[0]; + const commentId = urlParts[urlParts.length - 1].split('#')[1].replace('issuecomment-', ''); + const [owner, repo] = urlParts.slice(3, 5); + let orgName = owner; + let repoName = repo; + let messageBody = ''; + let eventTitle = ''; + + try { + const messageResponse = await github.request("GET /repos/{owner}/{repo}/issues/comments/{comment_id}", { + owner: owner, + repo: repo, + comment_id: commentId + }); + messageBody = messageResponse.data.body; + + const issueResponse = await github.rest.issues.get({ + owner, + repo, + issue_number: eventNumber + }); + eventTitle = issueResponse.data.title; + } catch (error) { + console.error(error); + } + + return { + orgName, + repoName, + eventNumber, + commentId, + messageBody, + eventTitle + }; + } + + } + catch (error) { + console.error('Error while running the vote_tracker workflow:', error); + } +} \ No newline at end of file diff --git a/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml b/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml index 66606fc17..02d71a796 100644 --- a/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml +++ b/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml @@ -59,7 +59,9 @@ jobs: body: `Hello, @${{ github.actor }}! 👋🏼 This PR is not up to date with the base branch and can't be merged. Please update your branch manually with the latest version of the base branch. - PRO-TIP: Add a comment to your PR with the text: \`/au\` or \`/autoupdate\` and our bot will take care of updating the branch in the future. The only requirement for this to work is to enable [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option in your PR. + PRO-TIP: To request an update from the upstream branch, simply comment \`/u\` or \`/update\` and our bot will handle the update operation promptly. + + The only requirement for this to work is to enable [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option in your PR. Also the update will not work if your fork is located in an organization, not under your personal profile. Thanks 😄` }) } diff --git a/.github/workflows/autoupdate.yml b/.github/workflows/autoupdate.yml index ad8e0198f..eeb77a47b 100644 --- a/.github/workflows/autoupdate.yml +++ b/.github/workflows/autoupdate.yml @@ -1,34 +1,34 @@ -# This action is centrally managed in https://github.com/asyncapi/.github/ -# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo - -# This workflow is designed to work with: -# - autoapprove and automerge workflows for dependabot and asyncapibot. -# - special release branches that we from time to time create in upstream repos. If we open up PRs for them from the very beginning of the release, the release branch will constantly update with new things from the destination branch they are opened against - -# It uses GitHub Action that auto-updates pull requests branches, whenever changes are pushed to their destination branch. -# Autoupdating to latest destination branch works only in the context of upstream repo and not forks - -name: autoupdate - -on: - push: - branches-ignore: - - 'version-bump/**' - - 'dependabot/**' - - 'bot/**' - - 'all-contributors/**' - -jobs: - autoupdate-for-bot: - if: startsWith(github.repository, 'asyncapi/') - name: Autoupdate autoapproved PR created in the upstream - runs-on: ubuntu-latest - steps: - - name: Autoupdating - uses: docker://chinthakagodawita/autoupdate-action:v1 - env: - GITHUB_TOKEN: '${{ secrets.GH_TOKEN_BOT_EVE }}' - PR_FILTER: "labelled" - PR_LABELS: "autoupdate" - PR_READY_STATE: "ready_for_review" - MERGE_CONFLICT_ACTION: "ignore" +# This action is centrally managed in https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +# This workflow is designed to work with: +# - autoapprove and automerge workflows for dependabot and asyncapibot. +# - special release branches that we from time to time create in upstream repos. If we open up PRs for them from the very beginning of the release, the release branch will constantly update with new things from the destination branch they are opened against + +# It uses GitHub Action that auto-updates pull requests branches, whenever changes are pushed to their destination branch. +# Autoupdating to latest destination branch works only in the context of upstream repo and not forks + +name: autoupdate + +on: + push: + branches-ignore: + - 'version-bump/**' + - 'dependabot/**' + - 'bot/**' + - 'all-contributors/**' + +jobs: + autoupdate-for-bot: + if: startsWith(github.repository, 'asyncapi/') + name: Autoupdate autoapproved PR created in the upstream + runs-on: ubuntu-latest + steps: + - name: Autoupdating + uses: docker://chinthakagodawita/autoupdate-action:v1 + env: + GITHUB_TOKEN: '${{ secrets.GH_TOKEN_BOT_EVE }}' + PR_FILTER: "labelled" + PR_LABELS: "autoupdate" + PR_READY_STATE: "ready_for_review" + MERGE_CONFLICT_ACTION: "ignore" diff --git a/.github/workflows/bounty-program-commands.yml b/.github/workflows/bounty-program-commands.yml new file mode 100644 index 000000000..645e0c90d --- /dev/null +++ b/.github/workflows/bounty-program-commands.yml @@ -0,0 +1,126 @@ +# This workflow is centrally managed at https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repository, as they will be overwritten with +# changes made to the same file in the abovementioned repository. + +# The purpose of this workflow is to allow Bounty Team members +# (https://github.com/orgs/asyncapi/teams/bounty_team) to issue commands to the +# organization's global AsyncAPI bot related to the Bounty Program, while at the +# same time preventing unauthorized users from misusing them. + +name: Bounty Program commands + +on: + issue_comment: + types: + - created + +env: + BOUNTY_PROGRAM_LABELS_JSON: | + [ + {"name": "bounty", "color": "0e8a16", "description": "Participation in the Bounty Program"} + ] + +jobs: + guard-against-unauthorized-use: + if: > + github.actor != ('aeworxet' || 'thulieblack') && + ( + startsWith(github.event.comment.body, '/bounty' ) + ) + + runs-on: ubuntu-latest + + steps: + - name: ❌ @${{github.actor}} made an unauthorized attempt to use a Bounty Program's command + uses: actions/github-script@v6 + + with: + github-token: ${{ secrets.GH_TOKEN }} + script: | + const commentText = `❌ @${{github.actor}} is not authorized to use the Bounty Program's commands. + These commands can only be used by members of the [Bounty Team](https://github.com/orgs/asyncapi/teams/bounty_team).`; + + console.log(`❌ @${{github.actor}} made an unauthorized attempt to use a Bounty Program's command.`); + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentText + }) + + add-label-bounty: + if: > + github.actor == ('aeworxet' || 'thulieblack') && + ( + startsWith(github.event.comment.body, '/bounty' ) + ) + + runs-on: ubuntu-latest + + steps: + - name: Add label `bounty` + uses: actions/github-script@v6 + + with: + github-token: ${{ secrets.GH_TOKEN }} + script: | + const BOUNTY_PROGRAM_LABELS = JSON.parse(process.env.BOUNTY_PROGRAM_LABELS_JSON); + let LIST_OF_LABELS_FOR_REPO = await github.rest.issues.listLabelsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + }); + + LIST_OF_LABELS_FOR_REPO = LIST_OF_LABELS_FOR_REPO.data.map(key => key.name); + + if (!LIST_OF_LABELS_FOR_REPO.includes(BOUNTY_PROGRAM_LABELS[0].name)) { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: BOUNTY_PROGRAM_LABELS[0].name, + color: BOUNTY_PROGRAM_LABELS[0].color, + description: BOUNTY_PROGRAM_LABELS[0].description + }); + } + + console.log('Adding label `bounty`...'); + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [BOUNTY_PROGRAM_LABELS[0].name] + }) + + remove-label-bounty: + if: > + github.actor == ('aeworxet' || 'thulieblack') && + ( + startsWith(github.event.comment.body, '/unbounty' ) + ) + + runs-on: ubuntu-latest + + steps: + - name: Remove label `bounty` + uses: actions/github-script@v6 + + with: + github-token: ${{ secrets.GH_TOKEN }} + script: | + const BOUNTY_PROGRAM_LABELS = JSON.parse(process.env.BOUNTY_PROGRAM_LABELS_JSON); + let LIST_OF_LABELS_FOR_ISSUE = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + LIST_OF_LABELS_FOR_ISSUE = LIST_OF_LABELS_FOR_ISSUE.data.map(key => key.name); + + if (LIST_OF_LABELS_FOR_ISSUE.includes(BOUNTY_PROGRAM_LABELS[0].name)) { + console.log('Removing label `bounty`...'); + github.rest.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: [BOUNTY_PROGRAM_LABELS[0].name] + }) + } diff --git a/.github/workflows/create-event-ad-hoc.yml b/.github/workflows/create-event-ad-hoc.yml index 8a5a0d1b4..6f232579b 100644 --- a/.github/workflows/create-event-ad-hoc.yml +++ b/.github/workflows/create-event-ad-hoc.yml @@ -30,7 +30,7 @@ jobs: meeting_desc: ${{ github.event.inputs.desc }} meeting_banner: ${{ github.event.inputs.meeting_banner }} host: lpgornicki@gmail.com - alternative_host: "fmvilas@gmail.com,jonas-lt@live.dk,devlopergene@gmail.com,sibanda.thulie@gmail.com" + alternative_host: "jonas-lt@live.dk,devlopergene@gmail.com,sibanda.thulie@gmail.com,alejandra.olvera.novack@gmail.com,samir.amzani@gmail.com,oluwabamikemi@gmail.com" issue_template_path: .github/workflows/create-event-helpers/issues_templates/ad-hoc.md create_zoom: true secrets: diff --git a/.github/workflows/create-event-community-meeting.yml b/.github/workflows/create-event-community-meeting.yml index f37e3044b..63f2fb3ea 100644 --- a/.github/workflows/create-event-community-meeting.yml +++ b/.github/workflows/create-event-community-meeting.yml @@ -23,7 +23,7 @@ jobs: meeting_name: Community Meeting meeting_desc: This is a community meeting to regularly talk in open about important topics around AsyncAPI Initiative. host: lpgornicki@gmail.com - alternative_host: 'fmvilas@gmail.com,devlopergene@gmail.com,sibanda.thulie@gmail.com' + alternative_host: 'devlopergene@gmail.com,sibanda.thulie@gmail.com' issue_template_path: .github/workflows/create-event-helpers/issues_templates/community.md create_zoom: true secrets: diff --git a/.github/workflows/create-event-lets-talk-about.yml b/.github/workflows/create-event-lets-talk-about.yml index 2942ee8ba..5d6d41756 100644 --- a/.github/workflows/create-event-lets-talk-about.yml +++ b/.github/workflows/create-event-lets-talk-about.yml @@ -27,7 +27,7 @@ jobs: meeting_banner: ${{ github.event.inputs.meeting_banner }} meeting_desc: The purpose of this meeting is to focus on contributors, focus on people that want to contribute to AsyncAPI Initiative but do not know how to do it. host: lpgornicki@gmail.com - alternative_host: 'fmvilas@gmail.com,devlopergene@gmail.com,sibanda.thulie@gmail.com' + alternative_host: 'devlopergene@gmail.com,sibanda.thulie@gmail.com' issue_template_path: .github/workflows/create-event-helpers/issues_templates/lets-talk-about-contrib.md create_zoom: false secrets: diff --git a/.github/workflows/create-event-spec-3-0.yml b/.github/workflows/create-event-spec-3-0.yml index 92da486f6..ff4d7f4cf 100644 --- a/.github/workflows/create-event-spec-3-0.yml +++ b/.github/workflows/create-event-spec-3-0.yml @@ -24,7 +24,7 @@ jobs: meeting_name: Spec 3.0 Meeting meeting_desc: This is the meeting for community member involved in works related to 3.0 release of AsyncAPI Specification. host: jonas-lt@live.dk - alternative_host: fmvilas@gmail.com + alternative_host: lpgornicki@gmail.com issue_template_path: .github/workflows/create-event-helpers/issues_templates/spec-3-0.md create_zoom: true secrets: diff --git a/.github/workflows/create-event-spec-3-docs.yml b/.github/workflows/create-event-spec-3-docs.yml index 4d2bda5b8..176b1e033 100644 --- a/.github/workflows/create-event-spec-3-docs.yml +++ b/.github/workflows/create-event-spec-3-docs.yml @@ -23,7 +23,7 @@ jobs: meeting_name: Spec 3.0 Docs Meeting meeting_desc: This is a open meeting to plan and write Spec 3.0 Docs. host: alejandra.olvera.novack@gmail.com - alternative_host: 'fmvilas@gmail.com,devlopergene@gmail.com,sibanda.thulie@gmail.com,jonas-lt@live.dk,lpgornicki@gmail.com' + alternative_host: 'devlopergene@gmail.com,sibanda.thulie@gmail.com,jonas-lt@live.dk,lpgornicki@gmail.com' issue_template_path: .github/workflows/create-event-helpers/issues_templates/spec-3-docs.md create_zoom: true secrets: diff --git a/.github/workflows/create-event-thinking-out-loud.yml b/.github/workflows/create-event-thinking-out-loud.yml index 656c33760..7b2dc7115 100644 --- a/.github/workflows/create-event-thinking-out-loud.yml +++ b/.github/workflows/create-event-thinking-out-loud.yml @@ -29,7 +29,7 @@ jobs: meeting_name: Thinking Out Loud meeting_desc: ${{ github.event.inputs.desc }} guest: ${{ github.event.inputs.guest }} - host: fmvilas@gmail.com + host: lpgornicki@gmail.com issue_template_path: .github/workflows/create-event-helpers/issues_templates/thinking-out-loud.md create_zoom: true secrets: diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index d4ba4a44c..3f4dcbc4c 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -31,9 +31,11 @@ jobs: At the moment the following comments are supported in pull requests: + - \`/please-take-a-look\` or \`/ptal\` - This comment will add a comment to the PR asking for attention from the reviewrs who have not reviewed the PR yet. - \`/ready-to-merge\` or \`/rtm\` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added - \`/do-not-merge\` or \`/dnm\` - This comment will block automerging even if all conditions are met and ready-to-merge label is added - - \`/autoupdate\` or \`/au\` - This comment will add \`autoupdate\` label to the PR and keeps your PR up-to-date to the target branch's future changes. Unless there is a merge conflict or it is a draft PR.` + - \`/autoupdate\` or \`/au\` - This comment will add \`autoupdate\` label to the PR and keeps your PR up-to-date to the target branch's future changes. Unless there is a merge conflict or it is a draft PR. (Currently only works for upstream branches.) + - \`/update\` or \`/u\` - This comment will update the PR with the latest changes from the target branch. Unless there is a merge conflict or it is a draft PR. NOTE: this only updates the PR once, so if you need to update again, you need to call the command again.` }) create_help_comment_issue: diff --git a/.github/workflows/issues-prs-notifications.yml b/.github/workflows/issues-prs-notifications.yml index 78ebe9601..b8b20c6ba 100644 --- a/.github/workflows/issues-prs-notifications.yml +++ b/.github/workflows/issues-prs-notifications.yml @@ -20,8 +20,6 @@ jobs: name: Notify slack on every new issue runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 - name: Convert markdown to slack markdown for issue uses: asyncapi/.github/.github/actions/slackify-markdown@master id: issuemarkdown @@ -40,8 +38,6 @@ jobs: name: Notify slack on every new pull request runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 - name: Convert markdown to slack markdown for pull request uses: asyncapi/.github/.github/actions/slackify-markdown@master id: prmarkdown @@ -60,8 +56,6 @@ jobs: name: Notify slack on every new pull request runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 - name: Convert markdown to slack markdown for pull request uses: asyncapi/.github/.github/actions/slackify-markdown@master id: discussionmarkdown diff --git a/.github/workflows/please-take-a-look-command.yml b/.github/workflows/please-take-a-look-command.yml new file mode 100644 index 000000000..b26cbc41a --- /dev/null +++ b/.github/workflows/please-take-a-look-command.yml @@ -0,0 +1,54 @@ +# This action is centrally managed in https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +# It uses Github actions to listen for comments on issues and pull requests and +# if the comment contains /please-take-a-look or /ptal it will add a comment pinging +# the code-owners who are reviewers for PR + +name: Please take a Look + +on: + issue_comment: + types: [created] + +jobs: + ping-for-attention: + if: > + github.event.issue.pull_request && + github.event.issue.state != 'closed' && + github.actor != 'asyncapi-bot' && + ( + contains(github.event.comment.body, '/please-take-a-look') || + contains(github.event.comment.body, '/ptal') || + contains(github.event.comment.body, '/PTAL') + ) + runs-on: ubuntu-latest + steps: + - name: Check for Please Take a Look Command + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GH_TOKEN }} + script: | + const prDetailsUrl = context.payload.issue.pull_request.url; + const { data: pull } = await github.request(prDetailsUrl); + const reviewers = pull.requested_reviewers.map(reviewer => reviewer.login); + + const { data: reviews } = await github.rest.pulls.listReviews({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + + const reviewersWhoHaveReviewed = reviews.map(review => review.user.login); + + const reviewersWhoHaveNotReviewed = reviewers.filter(reviewer => !reviewersWhoHaveReviewed.includes(reviewer)); + + if (reviewersWhoHaveNotReviewed.length > 0) { + const comment = reviewersWhoHaveNotReviewed.filter(reviewer => reviewer !== 'asyncapi-bot-eve' ).map(reviewer => `@${reviewer}`).join(' '); + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `${comment} Please take a look at this PR. Thanks! :wave:` + }); + } diff --git a/.github/workflows/slack-integration.yml b/.github/workflows/slack-integration.yml new file mode 100644 index 000000000..6bfa2fd7f --- /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' + - '.github/workflows/slack-integration.yml' + +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_INFRA_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 }}' 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..c2c373c0f --- /dev/null +++ b/.github/workflows/slack/README.md @@ -0,0 +1,151 @@ +## 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 😢. +- **You have to invite the bot to all managed channels to make it work.** + +> [!WARNING] +> **Creation of multitudes of groups leads to a lot of API calls and can lead to rate limiting. Please be cautious while creating groups, otherwise you will get `Error: couldn't get usergroups: slack rate limit exceeded, retry after 30s`**. Related issue (not fixed even thought it is closed): https://github.com/pablovarela/terraform-provider-slack/issues/64 + +> [!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..eeff3e129 --- /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, please open 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/.github/workflows/update-docs-on-docs-commits.yml b/.github/workflows/update-docs-on-docs-commits.yml new file mode 100644 index 000000000..b511e284d --- /dev/null +++ b/.github/workflows/update-docs-on-docs-commits.yml @@ -0,0 +1,57 @@ +# This workflow is centrally managed in https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +# The given workflow is responsible for generating docs and creating PR with them when there is a commit with docs: prefix + +# This workflow will be updated in all repos with the topic get-global-docs-autoupdate + +name: 'Update generated parts of documentation on docs: commits' + +on: + push: + branches: + - master + +jobs: + docs-gen: + name: 'Generate docs and create PR' + runs-on: ubuntu-latest + # PR should be created within this GH action only if it is a docs: commit + # Otherwise it will conflict with release workflow + if: startsWith(github.event.commits[0].message, 'docs:') + steps: + - name: Checkout repo + uses: actions/checkout@v4 + - name: Check package-lock version + uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master + id: lockversion + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ steps.lockversion.outputs.version }}" + cache: 'npm' + cache-dependency-path: '**/package-lock.json' + - name: Install dependencies + run: npm ci + - name: Regenerate docs + run: npm run generate:assets --if-present + - name: Create Pull Request with updated docs + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # uses 5.0.2 https://github.com/peter-evans/create-pull-request/releases/tag/v5.0.2 + with: + token: ${{ secrets.GH_TOKEN }} + commit-message: 'chore: update generated docs' + committer: asyncapi-bot + author: asyncapi-bot + title: 'chore: update generated docs' + body: 'Update of docs that are generated and were forgotten on PR level.' + branch: gen-docs-update/${{ github.job }} + - name: Report workflow status to Slack + if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel + uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 + with: + status: ${{ job.status }} + fields: repo,action,workflow + text: 'AsyncAPI docs generation workflow failed' + author_name: asyncapi-bot + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} \ No newline at end of file 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/.github/workflows/update-pr.yml b/.github/workflows/update-pr.yml new file mode 100644 index 000000000..2fa19b0ad --- /dev/null +++ b/.github/workflows/update-pr.yml @@ -0,0 +1,102 @@ +# This workflow is centrally managed in https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +# This workflow will run on every comment with /update or /u. And will create merge-commits for the PR. +# This also works with forks, not only with branches in the same repository/organization. +# Currently, does not work with forks in different organizations. + +# This workflow will be distributed to all repositories in the AsyncAPI organization + +name: Update PR branches from fork + +on: + issue_comment: + types: [created] + +jobs: + update-pr: + if: > + startsWith(github.repository, 'asyncapi/') && + github.event.issue.pull_request && + github.event.issue.state != 'closed' && ( + contains(github.event.comment.body, '/update') || + contains(github.event.comment.body, '/u') + ) + runs-on: ubuntu-latest + steps: + - name: Get Pull Request Details + id: pr + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} + previews: 'merge-info-preview' # https://docs.github.com/en/graphql/overview/schema-previews#merge-info-preview-more-detailed-information-about-a-pull-requests-merge-state-preview + script: | + const prNumber = context.payload.issue.number; + core.debug(`PR Number: ${prNumber}`); + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber + }); + + // If the PR has conflicts, we don't want to update it + const updateable = ['behind', 'blocked', 'unknown', 'draft', 'clean'].includes(pr.mergeable_state); + console.log(`PR #${prNumber} is ${pr.mergeable_state} and is ${updateable ? 'updateable' : 'not updateable'}`); + core.setOutput('updateable', updateable); + + core.debug(`Updating PR #${prNumber} with head ${pr.head.sha}`); + + return { + id: pr.node_id, + number: prNumber, + head: pr.head.sha, + } + - name: Update the Pull Request + if: steps.pr.outputs.updateable == 'true' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }} + script: | + const mutation = `mutation update($input: UpdatePullRequestBranchInput!) { + updatePullRequestBranch(input: $input) { + pullRequest { + mergeable + } + } + }`; + + const pr_details = ${{ steps.pr.outputs.result }}; + + try { + const { data } = await github.graphql(mutation, { + input: { + pullRequestId: pr_details.id, + expectedHeadOid: pr_details.head, + } + }); + } catch (GraphQLError) { + core.debug(GraphQLError); + if ( + GraphQLError.name === 'GraphqlResponseError' && + GraphQLError.errors.some( + error => error.type === 'FORBIDDEN' || error.type === 'UNAUTHORIZED' + ) + ) { + // Add comment to PR if the bot doesn't have permissions to update the PR + const comment = `Hi @${context.actor}. Update of PR has failed. It can be due to one of the following reasons: + - I don't have permissions to update this PR. To update your fork with upstream using bot you need to enable [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option in the PR. + - The fork is located in an organization, not under your personal profile. No solution for that. You are on your own with manual update. + - There may be a conflict in the PR. Please resolve the conflict and try again.`; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: comment + }); + + core.setFailed('Bot does not have permissions to update the PR'); + } else { + core.setFailed(GraphQLError.message); + } + } diff --git a/.github/workflows/vote-tracker.yml b/.github/workflows/vote-tracker.yml new file mode 100644 index 000000000..9b690aca8 --- /dev/null +++ b/.github/workflows/vote-tracker.yml @@ -0,0 +1,45 @@ +name: Vote Tracker + +on: + issue_comment: + types: [created] + + workflow_dispatch: + inputs: + bot_comment_url: + description: | + Provide URL pointing to gitvote bot comment that contains closing voting update. It looks like `https://github.com/asyncapi/community/issues/1313#issuecomment-2247595858`. We use this to update the voting summary in cases when we see errors in the voting status, when for example TSC member voted, but did a mistake and voted by adding emoji to main description or other bot comment instead of the correct way: which is adding an emoji to a comment from bot that opens the vote. + required: true + +jobs: + track-vote: + if: ${{ github.actor == 'git-vote[bot]' && contains(github.event.comment.body, 'Vote closed') || github.event_name == 'workflow_dispatch' }} + runs-on: ubuntu-latest + steps: + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Installing Module + run: npm install js-yaml@4.1.0 --no-save + shell: bash + + - name: Run GitHub Script + id: vote_tracker + uses: actions/github-script@v7 + with: + script: | + const script = require('./.github/scripts/vote_tracker.js'); + const botCommentURL = "${{ github.event.inputs.bot_comment_url || '' }}"; + await script({ github, context, botCommentURL }); + + - name: Create Pull Request to update Vote Tracking Details + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # uses 5.0.2 https://github.com/peter-evans/create-pull-request/releases/tag/v5.0.2 + with: + token: ${{ secrets.GH_TOKEN }} + commit-message: 'chore: update vote tracking details' + committer: asyncapi-bot + author: asyncapi-bot + title: 'chore: vote tracking details' + body: 'Update the TSC_VOTING_OVERVIEW.md and voteTrackingFile.json' + branch: vote-trackingupdate/${{ github.job }} diff --git a/.github/workflows/vote-verifcation.yml b/.github/workflows/vote-verifcation.yml new file mode 100644 index 000000000..dfd592b5c --- /dev/null +++ b/.github/workflows/vote-verifcation.yml @@ -0,0 +1,64 @@ +name: Verification of the Vote + +on: + issue_comment: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Verify the person + id: verify_member + uses: ./.github/actions/verifyTSCMember + with: + authorName: "${{github.event.comment.user.login}}" + + - name: Checking the person authenticity. + if: (github.event.comment.body == '/vote') || (github.event.comment.body == '/cancel-vote') + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GH_TOKEN_BOT_EVE }} + script : | + const isTSCMember = ${{ steps.verify_member.outputs.isTSCMember}} + if(!isTSCMember) { + const commentText = `Hi @${{ github.actor }}, since you are not a [TSC Member](https://www.asyncapi.com/community/tsc), you cannot start or stop voting. Please [read more about voting process](https://github.com/asyncapi/community/blob/master/voting.md)`; + console.log(`User ❌ @${{ github.actor }} is not a TSC Member`); + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentText + }); + } else if('${{github.actor}}' != 'git-vote[bot]') { + console.log(`User ✅ @${{ github.actor }} is a TSC Member`); + } + + - name: Add the label + run: | + if [ "${{steps.verify_member.outputs.isTSCMember}}" == "true" ]; then + if [ "${{ github.event.comment.body }}" == "/vote" ]; then + if [ "${{ github.event_name }}" != "pull_request" ]; then + gh issue edit ${{ github.event.issue.number }} --add-label "vote" + else + gh pr edit ${{ github.event.issue.number }} --add-label "vote" + fi + fi + fi + env: + GH_TOKEN: ${{ secrets.GH_TOKEN_BOT_EVE }} + - name: Remove the label + run: | + if [ "${{steps.verify_member.outputs.isTSCMember}}" == "true" ]; then + if [ "${{ github.event.comment.body }}" == "/cancel-vote" ]; then + if [ "${{ github.event_name }}" != "pull_request" ]; then + gh issue edit ${{ github.event.issue.number }} --remove-label "vote" + else + gh pr edit ${{ github.event.issue.number }} --remove-label "vote" + fi + fi + fi + env: + GH_TOKEN: ${{ secrets.GH_TOKEN_BOT_EVE }} diff --git a/.github/workflows/youtube-to-spotify-for-podcasters.yml b/.github/workflows/youtube-to-spotify-for-podcasters.yml index bd91f7b56..37b779d16 100644 --- a/.github/workflows/youtube-to-spotify-for-podcasters.yml +++ b/.github/workflows/youtube-to-spotify-for-podcasters.yml @@ -26,7 +26,7 @@ jobs: # Verify the content was written successfully cat episode.json - name: Upload Episode from YouTube To Anchor.Fm - uses: Schrodinger-Hat/youtube-to-anchorfm@c722f3edeee94f3173dad36c5a959247973c5253 #commit related to https://github.com/Schrodinger-Hat/youtube-to-anchorfm/commit/c722f3edeee94f3173dad36c5a959247973c5253 || The latest commit which is of Nov 14, 2023 + uses: Schrodinger-Hat/youtube-to-anchorfm@b02b82f809d24db88472a78c51ffa627f46a6dc3 #commit related to https://github.com/Schrodinger-Hat/youtube-to-anchorfm/commit/b02b82f809d24db88472a78c51ffa627f46a6dc3 || The latest commit which refers to v2.4.0 of the action env: ANCHOR_EMAIL: ${{ secrets.ANCHOR_EMAIL }} ANCHOR_PASSWORD: ${{ secrets.ANCHOR_PASSWORD }} 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/.gitvote.yml b/.gitvote.yml new file mode 100644 index 000000000..c1dffc24b --- /dev/null +++ b/.gitvote.yml @@ -0,0 +1,9 @@ +profiles: + default: + duration: 4w + pass_threshold: 51 + periodic_status_check: "1 week" + close_on_passing: true + allowed_voters: + teams: + - tsc_members \ No newline at end of file diff --git a/AMBASSADORS_MEMBERS.json b/AMBASSADORS_MEMBERS.json index c17915eb1..1eef57473 100644 --- a/AMBASSADORS_MEMBERS.json +++ b/AMBASSADORS_MEMBERS.json @@ -1,12 +1,12 @@ [ { - "name": "Alejandra Quetzalli", + "name": "Quetzalli Writes", "img": "https://avatars.githubusercontent.com/u/19964402?v=4", - "bio": "Alejandra Quetzalli is the upcoming author (2023) of the book titled 'Designing Developer Documentation as a Product', which will be published by the Apress Publishing Company. Alejandra has been in tech for 9 years, working with SEO, Paid Search, Full-Stack development, UX, Developer Relations, and Technical Writing (Engineering Documentation). She's currently a core OSS contributor for Docs, DevRel, and Community Building at AsyncAPI Initiative. She's also a member of the AsyncAPI Technical Steering Committee (TSC).", + "bio": "Quetzalli Writes is an author of the book titled 'Docs-as-Ecosystem', which was published by the Apress Publishing Company. Quetzalli has been in tech for 9 years, working with SEO, Paid Search, Full-Stack development, UX, Developer Relations, and Technical Writing (Engineering Documentation). She's currently a core OSS contributor for Docs, DevRel, and Community Building at AsyncAPI Initiative. She's also a member of the AsyncAPI Technical Steering Committee (TSC).", "title": "DevRel & DevDocs @AsyncAPI", - "github": "alequetzalli", - "twitter": "QuetzalliAle", - "linkedin": "alejandra-quetzalli", + "github": "quetzalliwrites", + "twitter": "QuetzalliWrites", + "linkedin": "quetzalli-writes", "company": "Postman", "country": "🇲🇽", "contributions": [ @@ -97,6 +97,55 @@ } ] }, + { + "name": "Giri Venkatesan", + "github": "gvensan", + "twitter": "giri_venkatesan", + "country": "🇮🇳", + "bio": "Giri Venkatesan, a follower and proponent of AsyncAPI and teams up with companies & SIs to design event-driven architecture and asynchronous APIs. To guide those discussions, I draw upon years of integration and implementation experience, particularly with Solace platforms. I've been a follower of AsyncAPI since 2022, and written blogs and delivered talks at conferences and AsyncAPI confrence tours.", + "linkedin": "girivenkatesan", + "company": "Solace", + "title": "Developer Advocate, Office of the CTO at Solace", + "img": "https://avatars.githubusercontent.com/u/4477169?s=96&v=4", + "contributions": [ + { + "type": "article", + "title": "Bridging Design and Runtime Gaps: AsyncAPI in Event-Driven Architecture", + "date": { + "year": 2024, + "month": "February" + }, + "link": "https://www.linux.com/news/bridging-design-and-runtime-gaps-asyncapi-in-event-driven-architecture/" + }, + { + "type": "talk", + "title": "Bridging the Gap between Design and Runtime in EDA with AsyncAPI and CI/CD", + "date": { + "year": 2023, + "month": "November" + }, + "link": "https://www.youtube.com/watch?v=CXt-fy82PCk" + }, + { + "type": "talk", + "title": "Bridging the Gap between Design and Runtime in EDA with AsyncAPI", + "date": { + "year": 2023, + "month": "August" + }, + "link": "https://www.youtube.com/watch?v=ewpADLeLNE4" + }, + { + "type": "article", + "title": "AsyncAPI + Spring Cloud Stream = Event-Driven Microservices Made Easy", + "date": { + "year": 2021, + "month": "November" + }, + "link": "https://www.youtube.com/watch?v=3EeMHhbwyOQ&t=4142s" + } + ] + }, { "name": "Hugo Guerrero", "img": "https://avatars.githubusercontent.com/u/1001939?v=4", @@ -154,6 +203,90 @@ } ] }, + { + "name": "Ivan Garcia Sainz-Aja", + "github": "ivangsa", + "twitter": "ivangsa", + "bio": "Java Architect with a deep understanding of Java, Spring-Boot, Spring-Cloud technologies, specializing in Domain-Driven Design (DDD) and Event-Driven Architectures creating Software Easy to Understand. Building ZenWave 360º. ZenWave 360º is a set of tools built on the foundations of Domain Driven Design and API-First principles for Event-Driven Architectures, to help you create software easy to understand. https://www.zenwave360.io/", + "linkedin": "ivangarciasainzaja", + "company": "IZERTIS", + "title": "Java Architect. Speaker. Building ZenWave 360°.", + "img": "https://avatars.githubusercontent.com/u/1246876?v=4", + "contributions": [ + { + "type": "iniciative_driver", + "title": "AsyncAPI Conference On Tour 2023 - Madrid", + "date": { + "year": 2023, + "month": "October" + }, + "link": "https://www.youtube.com/playlist?list=PLbi1gRlP7pihD-7XYb6c9wcTdkavDzF3_" + }, + { + "type": "iniciative_driver", + "title": "ZenWave SDK - Code Generator for AsyncAPI with Spring Cloud Streams", + "date": { + "year": 2024, + "month": "2022" + }, + "link": "https://www.zenwave360.io/zenwave-sdk/plugins/asyncapi-spring-cloud-streams3/" + }, + { + "type": "article", + "title": "API-First with AsyncAPI", + "date": { + "year": 2023, + "month": "March" + }, + "link": "https://www.zenwave360.io/posts/API-First-with-AsyncAPI-And-ZenWave-SDK/" + }, + { + "type": "article", + "title": "ZenWave AsyncAPI Code Generator", + "date": { + "year": 2023, + "month": "March" + }, + "link": "https://www.zenwave360.io/posts/ZenWave-AsyncAPI-Code-Generator/" + }, + { + "type": "article", + "title": "Generating AsyncAPI definition files from JDL with ZenWaveSDK", + "date": { + "year": 2023, + "month": "April" + }, + "link": "https://www.zenwave360.io/posts/JHipster-As-IDL-for-AsyncAPIv2/" + }, + { + "type": "presentation", + "title": "KIT - API-First with AsyncAPI for Event Driven Architectures", + "date": { + "year": 2023, + "month": "May" + }, + "link": "https://www.youtube.com/watch?v=EoWFZfmspFM" + }, + { + "type": "presentation", + "title": "Practical Event Storming with AsyncAPI v3 and ZenWave SDK", + "date": { + "year": 2023, + "month": "October" + }, + "link": "https://www.youtube.com/watch?v=-uHONzz-a6U" + }, + { + "type": "presentation", + "title": "Code Generation For Enterprise Integration Patterns w/ AsyncAPI & ZenWave SDK", + "date": { + "year": 2023, + "month": "October" + }, + "link": "https://www.youtube.com/watch?v=gUsoD8RaCuw" + } + ] + }, { "name": "Jesse Menning", "github": "jessemenning", @@ -415,5 +548,143 @@ "link": "https://www.youtube.com/watch?v=6Igp4DhK_hE" } ] + }, + { + "name": "Raphael De Lio", + "github": "raphaeldelio", + "twitter": "raphaeldelio", + "linkedin": "raphaeldelio", + "country": "🇧🇷", + "bio": "Raphael De Lio is a passionate software engineer who loves to think about solutions and ways to improve anything he touches. He was born in Brazil, lived in Portugal for five years, and now works as a consultant in the Netherlands. In his quest for knowledge, Raphael has always valued learning and sharing insights with others. This pursuit not only led him to Xebia, a place where he found a community of engineers who share his enthusiasm for technology and continuous improvement but also to becoming the co-organizer of the Amsterdam Kotlin MeetUp, where he has been able to enable other speakers to share their knowledge as well.", + "company": "Xebia", + "title": "Software Consultant at Xebia", + "img": "https://avatars.githubusercontent.com/u/25641721?v=4", + "contributions": [ + { + "type": "article", + "title": "AsyncAPI — A standard specification for documenting Event-Driven Applications", + "date": { + "year": 2024, + "month": "February" + }, + "link": "https://medium.com/@raphaeldelio/asyncapi-a-standard-for-documenting-event-driven-applications-8ff657119036" + }, + { + "type": "presentation", + "title": "AsyncAPI & Springwolf - Automated documentation (and more)", + "date": { + "year": 2024, + "month": "May" + }, + "link": "https://www.youtube.com/watch?v=DylvTW_ia4Y" + } + ] + }, + { + "name": "Hari Krishnan", + "github": "harikrishnan83", + "twitter": "harikrishnan83", + "linkedin": "harikrishnan83", + "country": "🇮🇳", + "bio": "Co-creator of Specmatic and Perfiz. I also advise organizations, both large and small, on their transformation journey. Apart from bringing ideas to life as working software products, I coach developers, project managers, product owners, and engineering leaders. I have spoken at several conferences, including AACoT 2023, API Specification Conference (#ASC2022), API World, SeleniumConf, Agile2021, Agile India, TestingUY 2021, SREConf, PyCon Singapore, RubyConf India. My areas of interest include distributed systems, concurrency, high-performance application architecture, coaching, and training.", + "company": "Specmatic and Polarizer Technologies", + "title": "Co-founder and CTO at Specmatic, Founder, and CEO at Polarizer Technologies", + "img": "https://raw.githubusercontent.com/harikrishnan83/harikrishnan83/master/HariKrishnan-profile.jpg", + "contributions": [ + { + "type": "talk", + "title": "Kafka and JMS Mocking with AsyncAPI", + "date": { + "year": 2023, + "month": "November" + }, + "link": "https://www.youtube.com/watch?v=9yRf75p_kTU" + }, + { + "type": "talk", + "title": "Unshackling Your System Under Test: Shift-Left Testing Through Dependency Isolation (Kafka Mocks with AsyncAPI specification)", + "date": { + "year": 2024, + "month": "June" + }, + "link": "https://confengine.com/conferences/selenium-conf-2024/proposal/20021/unshackling-your-system-under-test-shift-left-testing-through-dependency-isolation" + } + ] + }, + { + "name": "Manuel Ottlik", + "github": "manuelottlik", + "twitter": "", + "linkedin": "manuelottlik", + "country": "🇩🇪", + "bio": "Manuel is the Product Owner of the Global Integration Platform at HDI Global SE. He sold his first software at the age of thirteen and has been developing software ever since. After graduating, he joined the financial industry in API management and eventually moved to HDI Global SE to merge a service bus, API management and an event broker into an integration platform for the cloud division. In addition to his work at HDI Global SE, he is co-founder of a small company in the education software sector and freelance writer for heise.de and its magazines.", + "company": "HDI Global SE", + "title": "Product Owner Integration Platform & PBAC Platform", + "img": "https://avatars.githubusercontent.com/u/28919003?v=4", + "contributions": [ + { + "type": "talk", + "title": "Event-Driven Architecture und REST-APIs: Es gibt keine Konkurrenz!", + "date": { + "year": 2023, + "month": "April" + }, + "link": "" + }, + { + "type": "talk", + "title": "Event-driven Architecture and REST-APIs: It's not a competition", + "date": { + "year": 2023, + "month": "May" + }, + "link": "" + }, + { + "type": "talk", + "title": "Event-driven Architecture and REST-APIs: It's not a competition", + "date": { + "year": 2023, + "month": "September" + }, + "link": "" + }, + { + "type": "talk", + "title": "Event-Driven Architecture und REST-APIs: Es gibt keine Konkurrenz!", + "date": { + "year": 2023, + "month": "October" + }, + "link": "" + }, + { + "type": "talk", + "title": "Event-driven Architecture and REST-APIs: It's not a competition", + "date": { + "year": 2023, + "month": "December" + }, + "link": "https://drive.google.com/file/d/1KN-iuw0P4nOYNhnT15RQvgq5YqGy4ECC/view?usp=sharing" + }, + { + "type": "talk", + "title": "Eine Registry, sie alle zu knechten: Schemata von Entitäten mit xRegistry für alle Integrationsprodukte zentralisieren", + "date": { + "year": 2024, + "month": "April" + }, + "link": "" + }, + { + "type": "article", + "title": "AsyncAPI - HDI Global SE Case Study", + "date": { + "year": 2024, + "month": "July" + }, + "link": "https://www.asyncapi.com/casestudies/hdiglobal" + } + ] } ] diff --git a/CODEOWNERS b/CODEOWNERS index 02923fd32..aeff70244 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,4 +8,7 @@ * @alequetzalli @derberg @asyncapi-bot-eve @thulieblack # All ambassadors related files -AMBASSADOR* @Barbanio +AMBASSADOR* @thulieblack + +# Code Of Conduct +/code_of_conduct/ @asyncapi/code_of_conduct diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 638f73340..76d5ab213 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,46 +1,87 @@ -# Contributor Covenant Code of Conduct +# AsyncAPI Code of Conduct -## Our Pledge +## Introduction +Welcome to our community! We are a diverse group of individuals united by our passion for open source and commitment to inclusivity. -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +Our community promotes and supports inclusivity, welcoming individuals from all backgrounds and experiences. We believe that diversity is our strength, and we actively seek participation from those who enhance it. -## Our Standards +Our Code of Conduct governs how we behave publicly or privately when representing the project. It ensures that diverse groups collaborate for mutual advantage and enjoyment and challenges prejudice that could jeopardize anyone's participation in the project. + +We expect everyone in our community to treat each other with kindness, empathy, and respect. We believe fostering a welcoming and respectful environment can create a positive and successful community. + +## Our Pledge -Examples of behavior that contributes to creating a positive environment include: +As members, contributors, and admins of our community, we pledge to ensure that every individual is treated with respect and dignity. We pledge to create a safe, inclusive, and welcoming environment that is free from any form of harassment or discrimination regardless of differences in age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members +We pledge to encourage a diverse, healthy community that celebrates individuality and promotes equality. We will act and interact in ways that promote openness, empathy, understanding, and acceptance of everyone's unique perspectives and experiences. -Examples of unacceptable behavior by participants include: +## Our Standards -- The use of sexualized language or imagery and unwelcome sexual attention or advances -- Trolling, insulting/derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a professional setting +### Examples of behavior that contributes to a positive environment for our community include: -## Our Responsibilities +- Using welcoming and inclusive language. +- Being respectful of differing viewpoints and experiences. +- Gracefully accepting constructive criticism. +- Focusing on what is best for the community. +- Showing empathy towards other community members. -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. +### Examples of unacceptable behavior include: -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +- The use of sexualized language or imagery and unwelcome sexual attention or advances. +- Trolling, insulting/derogatory comments, and personal or political attacks. +- Public or private harassment. +- Publishing others' private information, such as a physical or electronic address, without explicit permission. +- Publishing content or comments that promote illegal activities. +- Violence, threats of violence, or violent language. +- Other conduct that could reasonably be considered inappropriate in a professional setting. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. +## Enforce Responsibilities + +The Code of Conduct Committee (CoC Committee) responds to, investigates, and resolves AsyncAPI Incidents. The Committee is responsible for clarifying the standards of acceptable behavior and taking appropriate and fair corrective action in response to unacceptable behavior. + +The Committee has the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that do not align with this Code of Conduct. The Committee may also temporarily or permanently ban any contributor for inappropriate, threatening, offensive, or harmful behaviors to the community. + +For more details, please see the [CoC Committee and Incident Resolution Procedure](https://github.com/asyncapi/community/pull/1013/files). + ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fmvilas@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at condcut@asyncapi.io. All complaints will be reviewed and investigated promptly and fairly. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction +Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +Consequence: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning +Community Impact: A violation through a single incident or series of actions. + +Consequence: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban +Community Impact: A serious violation of community standards, including sustained inappropriate behavior. + +Consequence: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban +Community Impact: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +Consequence: A permanent ban from any sort of public interaction within the community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [http://contributor-covenant.org/version/2/1][version]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. [homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +[version]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/inclusion diff --git a/Emeritus.yaml b/Emeritus.yaml index 100800335..c4d2cb040 100644 --- a/Emeritus.yaml +++ b/Emeritus.yaml @@ -3,3 +3,15 @@ emeritus: - jotamusik - LouisXhaferi - aeworxet + - arjungarg07 + - boyney123 + - Barbanio + - mcturco + - damaru-inc + - geraldloeffler + - ron-debajyoti + - char0n + - kieranm1999 + - jefflufc + - lewis-relph + - emilianozublena \ No newline at end of file diff --git a/MAINTAINERS.yaml b/MAINTAINERS.yaml index 07ae25c4f..e9c443ce7 100644 --- a/MAINTAINERS.yaml +++ b/MAINTAINERS.yaml @@ -1,5 +1,5 @@ - name: Aishat Muibudeen - github: mayaleeeee + github: Mayaleeeee linkedin: aishatmuibudeen slack: U03CNHGEUR1 twitter: maya_ux_ui @@ -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,17 @@ isTscMember: true repos: - website + githubID: 76521428 +- name: Ansh Goyal + github: anshgoyalevil + linkedin: thisisanshg + slack: U057J527M24 + twitter: thisisanshg + availableForHire: true + isTscMember: true + repos: + - website + githubID: 94157520 - name: Anand Sunderraman github: anandsunderraman linkedin: anand-sunderraman-a6b7a131 @@ -42,15 +58,7 @@ isTscMember: true repos: - go-watermill-template -- name: Arjun Garg - github: arjungarg07 - linkedin: arjungarg17 - slack: U01QX79S734 - twitter: ArjunGarg07 - availableForHire: true - isTscMember: true - repos: - - cupid + githubID: 4500774 - name: Ashish Padhy github: Shurtu-gal linkedin: ashish-padhy3023 @@ -60,16 +68,20 @@ isTscMember: true repos: - github-action-for-cli + - cli + githubID: 100484401 - name: Cameron Rushton - github: cameronrushton + github: CameronRushton slack: U01DVKKAV5K availableForHire: false 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,48 +91,53 @@ 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 slack: U01LYC8PW0M availableForHire: false - isTscMember: true + isTscMember: false repos: - - asyncapi-php-template + - php-template + githubID: 466639 - name: Fran Méndez github: fmvilas slack: U34F2JRRS availableForHire: false - company: Postman linkedin: fmvilas isTscMember: true repos: - - raml-dt-schema-parser - - avro-schema-parser - - openapi-schema-parser - - asyncapi-react - - glee - - generator - - nodejs-template - - nodejs-ws-template - - parser-js - - playground - spec - spec-json-schemas - - website + - 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 + github: GeraldLoeffler linkedin: geraldloeffler slack: U01P5QDLP0X availableForHire: false - company: Salesforce - isTscMember: true + isTscMember: false repos: + - spec-json-schemas - bindings + githubID: 1985716 - name: Jonas Lagoni github: jonaslagoni linkedin: jonaslagoni @@ -129,16 +146,20 @@ 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 + github: KhudaDad414 twitter: KhudaDadNomani linkedin: khudadadnomani slack: U01RVRD1TCL @@ -146,29 +167,35 @@ company: Postman isTscMember: true repos: - - bindings - - glee + - spec-json-schemas + - studio - .github - optimizer + - glee + githubID: 32505158 - name: Laurent Broudoux github: lbroudoux twitter: lbroudoux linkedin: laurentbroudoux slack: U018NLDV5E1 availableForHire: false + company: Postman isTscMember: true repos: + - spec-json-schemas - bindings + githubID: 1538635 - name: Ludovic Dussart - github: m3lkior + github: M3lkior linkedin: ludovic-dussart-846a8063 slack: U01BM49KL3Z twitter: ldussart availableForHire: false - company: Ineat + company: zatsit isTscMember: true repos: - avro-schema-parser + githubID: 5501911 - name: Lukasz Gornicki github: derberg linkedin: lukasz-gornicki-a621914 @@ -178,97 +205,105 @@ company: Postman isTscMember: true repos: - - avro-schema-parser - - openapi-schema-parser - - chatbot - - diff - - cli - - 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 - - parser-js - - playground - - spec - - spec-json-schemas + - java-spring-template + - github-action-for-cli + - .github + - jasyncapi + - generator-hooks + - vs-asyncapi-preview - template-for-generator-templates - - website - - bundler + - community + - diff + - chatbot + - infra + githubID: 6995927 - name: Maciej Urbańczyk github: magicmatatjahu availableForHire: false linkedin: maciej-urbańczyk-909547164 slack: U01EB02BP7A - company: Postman + company: Travelping GmbH isTscMember: true repos: + - website + - generator - asyncapi-react - - chatbot - - cli + - parser-go + - parser-js + - converter-js - converter-go - - event-gateway - - 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 - - playground - - server-api - template-for-go-projects - - website + - diff + - chatbot + - server-api + - EDAVisualiser + - problem + githubID: 20404945 - name: Azeez Elegbede linkedin: acebuild - github: acethecreator + github: AceTheCreator twitter: _acebuild slack: U01RWDD69PZ company: Postman availableForHire: false isTscMember: true repos: + - conference-website - chatbot + githubID: 40604284 - name: Michael Davis github: damaru-inc availableForHire: false slack: UH3B166TD - company: Solace - isTscMember: true + 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: true - repos: - - brand - - design-system - - studio - - website + githubID: 3926925 - name: Nektarios Fifes - github: nektariosfifes + github: NektariosFifes linkedin: nektarios-fifes-372740220 slack: U01SE93Q48N availableForHire: true isTscMember: true repos: - simulator + githubID: 61620751 - name: Pavel Bodiachevskii - github: pakisan + github: Pakisan slack: U0132LQU8C9 twitter: pbodiachevskii availableForHire: false isTscMember: true repos: + - spec-json-schemas + - tck - jasyncapi + - jasyncapi-idea-plugin + githubID: 3388414 - name: Philip Schlesinger github: theschles slack: U054UUYBNLF @@ -277,6 +312,7 @@ isTscMember: true repos: - jasyncapi-idea-plugin + githubID: 901430 - name: Prince Rajpoot github: princerajpoot20 linkedin: princerajpoot @@ -286,6 +322,7 @@ isTscMember: true repos: - studio + githubID: 44585452 - name: Richard Coppen github: rcoppen linkedin: richard-coppen @@ -294,7 +331,9 @@ company: IBM isTscMember: true repos: + - spec-json-schemas - bindings + githubID: 30902631 - name: Samir AMZANI github: Amzani slack: U01N6AW5V5G @@ -305,6 +344,8 @@ isTscMember: true repos: - studio + - cli + githubID: 554438 - name: Sergio Moya github: smoya linkedin: smoya @@ -314,19 +355,23 @@ company: Postman isTscMember: true repos: - - bindings + - spec + - spec-json-schemas + - parser-go + - parser-js - converter-go - - event-gateway + - bindings + - raml-dt-schema-parser + - openapi-schema-parser + - avro-schema-parser - go-watermill-template - - infra + - template-for-go-projects - parser-api - - parser-go - server-api - - spec - - spec-json-schemas - - template-for-go-projects + - infra + githubID: 1083296 - name: Souvik De - github: souvikns + github: Souvikns slack: U01SGCZMJKW twitter: souvik_ns linkedin: souvik-de-a2b941169 @@ -335,22 +380,22 @@ isTscMember: true repos: - cli - - bundler - glee -- name: Alejandra Quetzalli - github: alequetzalli - twitter: QuetzalliAle + - bundler + githubID: 41781438 +- name: Quetzalli Writes + github: quetzalliwrites + twitter: QuetzalliWrites slack: U02AKC14WAJ - linkedin: alejandra-quetzalli + linkedin: quetzalli-writes availableForHire: false company: Postman isTscMember: true repos: - website - - training - - community + githubID: 19964402 - name: David Pereira - github: bolt04 + github: BOLT04 twitter: BOLT2938 slack: U02EC8BT0TX linkedin: josé-david-pereira-13ba5315a @@ -359,61 +404,56 @@ isTscMember: true repos: - server-api + githubID: 18630253 - name: Daniel Raper github: dan-r slack: U02FP8WBFQE linkedin: danielr availableForHire: false - company: IBM isTscMember: true repos: - java-template + githubID: 1384852 - name: Kieran Murphy - github: kieranm1999 + github: KieranM1999 linkedin: kieran-murphy-175b0412b availableForHire: false slack: U02FT2TKM37 company: IBM - isTscMember: true + isTscMember: false repos: - java-template + githubID: 45017928 - name: Tom Jefferson - github: jefflufc + github: JEFFLUFC linkedin: t-jefferson slack: U02FPPCEH6H availableForHire: false company: IBM - isTscMember: true + isTscMember: false repos: - java-template + githubID: 54025356 - name: Lewis Relph github: lewis-relph availableForHire: false slack: U02G8MDDEF3 company: IBM - isTscMember: true + isTscMember: false repos: - java-template -- name: David Boyne - github: boyney123 - twitter: boyney123 - slack: U020GN9C6FM - availableForHire: false - company: AWS - isTscMember: true - repos: - - studio - - cli + githubID: 91530893 - name: Semen Tenishchev - github: tenischev + github: Tenischev linkedin: semen-tenishchev availableForHire: true slack: U011D1DAU6S isTscMember: true repos: - java-spring-template + githubID: 4137916 - name: Samridhi Agrawal - github: samridhi-98 + github: Samridhi-98 slack: U02T2MY9W5T linkedin: samridhi-agrawal-1713201ab availableForHire: false @@ -421,16 +461,7 @@ isTscMember: true repos: - modelina -- name: Debajyoti Halder - github: ron-debajyoti - twitter: rondebajyoti - slack: U02UK9RUPGQ - linkedin: rondebajyoti - availableForHire: false - company: Narvar - isTscMember: true - repos: - - modelina + githubID: 54466041 - name: Ivan Garcia Sainz-Aja github: ivangsa linkedin: ivangarciasainzaja @@ -440,8 +471,9 @@ isTscMember: true repos: - vs-asyncapi-preview + githubID: 1246876 - name: Florence Njeri - github: florence-njeri + github: Florence-Njeri linkedin: florencenjeri slack: U03D18YKX2M twitter: njericodes @@ -449,6 +481,7 @@ isTscMember: true repos: - generator + githubID: 40742916 - name: Jeremy Whitlock github: whitlockjc linkedin: whitlockjc @@ -458,7 +491,9 @@ company: Google isTscMember: true repos: + - spec-json-schemas - bindings + githubID: 98899 - name: Vladimír Gorej github: char0n linkedin: vladimirgorej @@ -466,31 +501,24 @@ twitter: vladimirgorej availableForHire: false company: SmartBear - isTscMember: true + 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 -- name: Barbaño González - linkedin: barbano-gonzalez-moreno - twitter: BarbanoGonzalez - github: barbanio - slack: U01J42QDSLU - availableForHire: false - company: Postman - isTscMember: true - repos: - - training - - community + - saunter + githubID: 5294032 - name: Kenneth Aasan github: kennethaasan slack: U037S2HK4TS @@ -500,14 +528,19 @@ isTscMember: true repos: - modelina + githubID: 1437394 - name: Heiko Henning - github: greenrover + github: GreenRover slack: U03AC4G51H8 availableForHire: false company: mtrail GmbH isTscMember: true repos: + - spec + - spec-json-schemas + - bindings - protobuf-schema-parser + githubID: 512850 - name: connil github: connil slack: U03A51H8 @@ -516,6 +549,7 @@ isTscMember: false repos: - dotnet-rabbitmq-template + githubID: 6583798 - name: mr-nuno github: mr-nuno slack: U03A5145 @@ -524,6 +558,7 @@ isTscMember: false repos: - dotnet-rabbitmq-template + githubID: 1067841 - name: Thulisile Sibanda github: thulieblack linkedin: v-thulisile-sibanda @@ -534,7 +569,9 @@ isTscMember: true repos: - website + - conference-website - community + githubID: 66913810 - name: Ashmit JaiSarita Gupta github: devilkiller-ag linkedin: jaisarita @@ -543,4 +580,173 @@ availableForHire: true isTscMember: true repos: - - modelina \ No newline at end of file + - modelina + githubID: 43639341 +- name: Sambhav Gupta + github: sambhavgupta0705 + linkedin: sambhavgupta0705 + twitter: sambhavgupta75 + slack: U04630DU3N3 + availableForHire: true + isTscMember: true + repos: + - website + githubID: 81870866 +- name: Viacheslav Turovskyi + github: aeworxet + slack: U01G3U01SVC + availableForHire: false + isTscMember: false + repos: + - 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/README.md b/README.md index c20b9ecb2..ed64c49f3 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Akshit Gupta
Akshit Gupta

📖 nikhilkalburgi
nikhilkalburgi

📖 + Giri Venkatesan
Giri Venkatesan

📢 📝 📣 diff --git a/TSC_MEMBERS.json b/TSC_MEMBERS.json index e0577da96..07e2a0cdd 100644 --- a/TSC_MEMBERS.json +++ b/TSC_MEMBERS.json @@ -170,12 +170,12 @@ }, { "name": "Ludovic Dussart", - "github": "m3lkior", + "github": "M3lkior", "linkedin": "ludovic-dussart-846a8063", "slack": "U01BM49KL3Z", "twitter": "ldussart", "availableForHire": false, - "company": "Ineat", + "company": "zatsit", "repos": [ "avro-schema-parser" ] @@ -548,19 +548,6 @@ "bindings" ] }, - { - "name": "Barbaño González", - "linkedin": "barbano-gonzalez-moreno", - "twitter": "BarbanoGonzalez", - "github":"Barbanio", - "slack":"U01J42QDSLU", - "availableForHire": false, - "company": "Postman", - "repos": [ - "training", - "community" - ] - }, { "name": "Kenneth Aasan", "github": "kennethaasan", 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/TSC_VOTING_OVERVIEW.md b/TSC_VOTING_OVERVIEW.md new file mode 100644 index 000000000..e26e325d6 --- /dev/null +++ b/TSC_VOTING_OVERVIEW.md @@ -0,0 +1,42 @@ + +| name | [Donate kotlin-asyncapi](https://github.com/asyncapi/community/issues/1313) | [Proposal for Admin Rights for CoC Main Committee on Slack](https://github.com/asyncapi/community/issues/1227) | [chore: add Marketing WORKING_GROUP](https://github.com/asyncapi/community/issues/1130) | [docs: add instruction how voting automation works](https://github.com/asyncapi/community/issues/1155) | lastParticipatedVoteTime | isVotedInLast3Months | lastVoteClosedTime | agreeCount | disagreeCount | abstainCount | notParticipatingCount | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| [Mayaleeeee](https://github.com/Mayaleeeee) | 👍 | 👍 | 👍 | 👍 | 2024-07-17 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [aayushmau5](https://github.com/aayushmau5) | 🔕 | 👍 | 👍 | 🔕 | 2024-05-28 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [imabp](https://github.com/imabp) | 👍 | 👍 | 🔕 | 👍 | 2024-07-23 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [akshatnema](https://github.com/akshatnema) | 👍 | 👍 | 👍 | 👍 | 2024-07-23 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [anshgoyalevil](https://github.com/anshgoyalevil) | 👍 | 👍 | 👍 | 🔕 | 2024-07-23 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [anandsunderraman](https://github.com/anandsunderraman) | 👍 | 👍 | 🔕 | 👍 | 2024-07-23 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [Shurtu-gal](https://github.com/Shurtu-gal) | 👍 | 👍 | 👍 | 👍 | 2024-07-17 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [CameronRushton](https://github.com/CameronRushton) | 🔕 | 👀 | 🔕 | 👍 | 2024-06-13 | true | 2024-07-26 | 1 | 0 | 1 | 2 | +| [dalelane](https://github.com/dalelane) | 👍 | 👀 | 🔕 | 🔕 | 2024-07-17 | true | 2024-07-26 | 1 | 0 | 1 | 2 | +| [fmvilas](https://github.com/fmvilas) | 🔕 | 👍 | 👍 | 👍 | 2024-05-28 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [jonaslagoni](https://github.com/jonaslagoni) | 👍 | 👍 | 👍 | 👍 | 2024-07-16 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [KhudaDad414](https://github.com/KhudaDad414) | 🔕 | 👍 | 👍 | 👍 | 2024-05-29 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [lbroudoux](https://github.com/lbroudoux) | 👍 | 👍 | 👍 | 🔕 | 2024-07-16 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [M3lkior](https://github.com/M3lkior) | 🔕 | 🔕 | 🔕 | 👍 | 2024-04-12 | true | 2024-07-26 | 1 | 0 | 0 | 3 | +| [derberg](https://github.com/derberg) | 👍 | 👍 | 👍 | 👍 | 2024-07-16 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [magicmatatjahu](https://github.com/magicmatatjahu) | 🔕 | 👍 | 👍 | 👍 | 2024-06-13 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [AceTheCreator](https://github.com/AceTheCreator) | 🔕 | 👍 | 👍 | 🔕 | 2024-05-29 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [NektariosFifes](https://github.com/NektariosFifes) | 🔕 | 🔕 | 🔕 | 🔕 | Member has not participated in all previous voting process. | Member has not participated in all previous voting process. | 2024-07-26 | 0 | 0 | 0 | 4 | +| [Pakisan](https://github.com/Pakisan) | 👍 | 🔕 | 👍 | 👍 | 2024-07-16 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [theschles](https://github.com/theschles) | 👍 | 🔕 | 🔕 | 👍 | 2024-07-18 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [princerajpoot20](https://github.com/princerajpoot20) | 🔕 | 👍 | 👍 | 👍 | 2024-05-28 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [rcoppen](https://github.com/rcoppen) | 👍 | 🔕 | 🔕 | 🔕 | 2024-07-17 | true | 2024-07-26 | 1 | 0 | 0 | 3 | +| [Amzani](https://github.com/Amzani) | 🔕 | 👍 | 👍 | 🔕 | 2024-06-13 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [smoya](https://github.com/smoya) | 👍 | 👍 | 👍 | 🔕 | 2024-07-23 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [Souvikns](https://github.com/Souvikns) | 👍 | 👍 | 🔕 | 👍 | 2024-07-17 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [quetzalliwrites](https://github.com/quetzalliwrites) | 🔕 | 👍 | 👍 | 👍 | 2024-06-04 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [BOLT04](https://github.com/BOLT04) | 🔕 | 👍 | 👍 | 🔕 | 2024-06-08 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [dan-r](https://github.com/dan-r) | 👍 | 🔕 | 🔕 | 🔕 | 2024-07-22 | true | 2024-07-26 | 1 | 0 | 0 | 3 | +| [Tenischev](https://github.com/Tenischev) | 👍 | 🔕 | 🔕 | 🔕 | 2024-07-16 | true | 2024-07-26 | 1 | 0 | 0 | 3 | +| [Samridhi-98](https://github.com/Samridhi-98) | 👍 | 🔕 | 🔕 | 👍 | 2024-07-16 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [ivangsa](https://github.com/ivangsa) | 👍 | 🔕 | 🔕 | 👍 | 2024-07-17 | true | 2024-07-26 | 2 | 0 | 0 | 2 | +| [Florence-Njeri](https://github.com/Florence-Njeri) | 👍 | 👍 | 👍 | 👍 | 2024-07-23 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [whitlockjc](https://github.com/whitlockjc) | 🔕 | 👍 | 🔕 | 🔕 | 2024-06-13 | true | 2024-07-26 | 1 | 0 | 0 | 3 | +| [VisualBean](https://github.com/VisualBean) | 👀 | 👍 | 👍 | 👍 | 2024-07-22 | true | 2024-07-26 | 3 | 0 | 1 | 0 | +| [kennethaasan](https://github.com/kennethaasan) | 👍 | 👍 | 👍 | 👍 | 2024-07-23 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [GreenRover](https://github.com/GreenRover) | 👍 | 🔕 | 🔕 | 👍 | 2024-07-24 | true | 2024-07-26 | 1 | 0 | 0 | 3 | +| [thulieblack](https://github.com/thulieblack) | 👍 | 👍 | 👍 | 👍 | 2024-07-20 | true | 2024-07-26 | 4 | 0 | 0 | 0 | +| [devilkiller-ag](https://github.com/devilkiller-ag) | 🔕 | 👍 | 👍 | 👍 | 2024-05-28 | true | 2024-07-26 | 3 | 0 | 0 | 1 | +| [sambhavgupta0705](https://github.com/sambhavgupta0705) | 👍 | 🔕 | 👍 | 👍 | 2024-07-24 | true | 2024-07-26 | 3 | 0 | 0 | 1 | \ No newline at end of file diff --git a/WORKING_GROUPS.md b/WORKING_GROUPS.md new file mode 100644 index 000000000..bb7bb09ea --- /dev/null +++ b/WORKING_GROUPS.md @@ -0,0 +1,35 @@ +### Definition of a Working Group + +A Working Group is a group of people in our community who share a common interest beyond GitHub repositories. + +A Working Group must have at least one of its members appointed as its **chairperson**. +The selection of the chairperson is done by the members of the group. Volunteers can be chairpersons, or the group can decide to elect one. The chairperson can also resign if they feel they can't fulfill their duties anymore. In this case, the group must elect a new chairperson if there is no other chairperson in the group. +The role of the chairperson is to facilitate the group meets its goals by removing blockers, ensuring the group works efficiently and is aligned with the AsyncAPI Roadmap. The chairperson is also responsible for running meetings effectively, ensuring that all members have a voice and that the group works in a transparent manner. +Multiple chairpersons can be elected if the working group members decide it's necessary. The way they share responsibilities is decided by the group. + +Anyone can create a Working Group. The only prerequisites are to have at least 3 founding members and the approval of the TSC (Technical Steering Committee). + +A Working Group should have clearly defined goals that are easily accessible to everyone on the internet, as this helps maintain alignment within the group. + +It is recommended that the Working Group has an associated project management tool like [GitHub Projects](https://docs.github.com/en/issues/planning-and-tracking-with-projects/creating-projects/creating-a-project) (or any other project management tool) to outline their roadmap. It's up to the Working Group to decide the structure of the project. E.g., Kanban, Shape Up, TO-DO list, etc. + +The group's name, members, goals, and other relevant information must be added to the `WORKING_GROUPS.yaml` file in the `community` repository. + +A Working Group has no authority or power over the roadmap of the projects they may impact. It's up to the repositories' maintainers (code owners) to approve or reject the pull requests. Therefore, it's advisable to either have maintainers of the impacted projects in the Working Group or ensure everyone agrees on the roadmap of the different repositories/projects. + +A Working Group must discuss ideas and solutions in public, and communicate through official channels all relevant discussions and implementations that want to suggest to others. + +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 new file mode 100644 index 000000000..6f8e4c3c6 --- /dev/null +++ b/WORKING_GROUPS.yaml @@ -0,0 +1,203 @@ +# This file contains the list of the currently active working groups. +# +# To learn more about working groups, read the WORKING_GROUPS.md file. + +working_groups: + # - name: Required. The name of the working group. + # description: Required. Describe what this working group is about. + # chairpersons: # Required to have at least 1 chairperson. In case of multiple, and unless specified, the first one is the primary chairperson. + # - name: Fran Méndez # Required. Name of the chairperson. + # github: fmvilas # Required. GitHub handle of the chairperson without the @. + # slack: U34F2JRRS # Required. Slack user ID of the chairperson. + # members: # Required to have at least 2 members who are not the same as the chairperson(s). + # - name: Sergio Moya # Required. Name of the member. + # github: smoya # Required. GitHub handle of the member without the @. + # slack: UN22ZTLHG # Required. Slack user ID of the member. + # slack: + # channel: + # handle: # Required. The handle of the Slack channel in the AsyncAPI workspace. Recommended pattern: wg-. Example: wg-maintainers-growth. + # description: # Recommended. A brief description of the working group to be used in the Slack channel description. If not provided, the wg description will be used. + # topic: # Optional. The topic of the Slack channel. + # group: + # handle: # Optional. The handle of the Slack group in the AsyncAPI workspace. Recommended pattern: wg-. Example: maintainers-growth-wg. If not provided, the name of the wg will be used and transformed to follow the recommended pattern. The handle should be unique and not in use by a member, channel, or another group. + # name: # Optional. The name of the Slack group. (If not provided, the name of the group will be autogenerated based on the name of the wg). + # description: # Recommended. The description of the Slack group. (If not provided, the description of the wg will be used). + # objectives: # Recommended. List of sentences outlining the objectives of the working group; or Link to a GitHub project, issue, or any other tool where the Working Group outlines their objectives. + # - The AsyncAPI community grows sustainably. + # roadmap_url: https://example.com/xyz # Recommended. Link to a GitHub project, issue, or any other tool where the Working Group outlines their roadmap. + # github_team: # Recommended. The GitHub team handle to tag all the working group members at once. Example: maintainers_growth_wg, without @asyncapi/ prefix. + + - name: Marketing + description: 'The group is dedicated to leveraging marketing strategies to achieve two key objectives: promoting AsyncAPI adoption and highlighting community achievements. By strategically showcasing AsyncAPI capabilities and celebrating community successes, the group drives both user growth and community engagement. It shares a vision of close collaboration between AsyncAPI community and sponsors.' + chairpersons: + - name: Oluwabamikemi Kayode + github: iambami + slack: U070DE02VQX + members: + - name: Lukasz Gornicki + github: derberg + slack: UD698Q5LM + - name: Aishat Muibudeen + github: Mayaleeeee + slack: U03CNHGEUR1 + - name: Thulisile Sibanda + github: thulieblack + slack: U03CNJPMT7C + - name: Christophe Dujarric + github: ChristopheDujarric + slack: U048TMNQ1M0 + - name: Georgie from Gravitee.io + github: Georgie-Gravitee + slack: U043BE3QUS2 + slack: + channel: + handle: wg-marketing + topic: Tasks board https://github.com/orgs/asyncapi/projects/46 + group: + handle: marketing-wg + name: Marketing Working Group + roadmap_url: https://github.com/orgs/asyncapi/projects/46 + github_team: marketing_wg + + - name: 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 languages. + chairpersons: + - name: Jonas Lagoni + github: jonaslagoni + slack: UQ2ANBG1E + members: + - name: Michael Wildman + github: m-wild + slack: UNH2HT346 + - name: Lorenz Simon + github: lorenzsimon + slack: U06L7EQQSF2 + - name: Alex Wichmann + github: VisualBean + slack: U04C58GB8TF + - name: Pavel Bodiachevskii + github: pakisan + slack: U0132LQU8C9 + - name: Souvik De + github: Souvikns + slack: U01SGCZMJKW + 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: ' + group: + handle: essential-building-blocks-wg + description: Essential Building Blocks Working Group + slack_channel: essential-building-blocks-wg + roadmap_url: https://github.com/orgs/asyncapi/projects/44 + github_team: essential_building_blocks_wg + objectives: + - https://github.com/orgs/asyncapi/projects/44 + + - name: Developer Experience + description: The goal of this group is to empower AsyncAPI user journey trough intuitive onboarding, tools, and a frictionless experience. + chairpersons: + - name: Samir Amzani + github: amzani + slack: U01N6AW5V5G + members: + - name: Pavel Bodiachevskii + github: pakisan + slack: U0132LQU8C9 + - name: Khuda Dad Nomani + github: KhudaDad414 + slack: U01RVRD1TCL + - name: Iván García Sainz-Aja + github: ivangsa + slack: UTCN3ET4M + - name: Pedro Ramos + github: peter-rr + slack: U01TP1KJV1R + - name: Ashish Padhy + github: Shurtu-gal + slack: U0572R8J927 + - name: Prince Rajpoot + github: princerajpoot20 + slack: U04STTQHV18 + - name: Aishat Muibudeen + github: Mayaleeeee + slack: U03CNHGEUR1 + - name: Fran Méndez + github: fmvilas + slack: U34F2JRRS + - name: Aayush Saini + github: AayushSaini101 + slack: U04RN9LRV97 + slack: + 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: ' + group: + handle: dx_wg + roadmap_url: https://shapeit.app/projects/org/asyncapi/16 + objectives: + - https://github.com/users/Amzani/projects/12/views/1 + github_team: developer_experience_wg + + - name: Maintainers Growth + description: The Maintainers Growth Working Group aims to help grow the number of maintainers at AsyncAPI. + chairpersons: + - name: Sergio Moya + github: smoya + slack: UN22ZTLHG + - name: Alejandra Quetzalli + github: alequetzalli + slack: U02AKC14WAJ + members: + - name: Elegbede Azeez + github: AceTheCreator + slack: U01RWDD69PZ + - name: Aishat Muibudeen + github: Mayaleeeee + slack: U03CNHGEUR1 + - name: Thulisile Sibanda + github: thulieblack + slack: U03CNJPMT7C + - name: Fran Méndez + github: fmvilas + slack: U34F2JRRS + slack: + channel: + handle: wg-maintainers-growth + description: This is the channel for the Maintainers Growth Working Group. + group: + handle: maintainers-growth-wg + description: Maintainers Growth Working Group + github_team: maintainers_growth_wg + + - name: Conference Coordination + description: The goal of the group is to plan, manage, and create a seamless way to enhance the conference experience. + chairpersons: + - name: Thulisile Sibanda + github: thulieblack + slack: U03CNJPMT7C + members: + - name: Thulisile Sibanda + github: thulieblack + slack: U03CNJPMT7C + - name: Lukasz Gornicki + github: derberg + slack: UD698Q5LM + - name: Oluwabamikemi Kayode + github: iambami + slack: U070DE02VQX + - name: Aishat Muibudeen + github: Mayaleeeee + slack: U03CNHGEUR1 + - name: Azeez Elegbede + github: acethecreator + slack: U01RWDD69PZ + slack: + channel: + handle: wg-conference-coordination + description: 'The Conference Coordination Working Group aims to plan, manage, and create a seamless way to enhance the conference experience. GitHub Project: https://github.com/orgs/asyncapi/projects/43/views/2' + roadmap_url: https://github.com/orgs/asyncapi/projects/43/views/2 + objectives: + - https://github.com/orgs/asyncapi/projects/43/views/2 + github_team: conference_coordination_wg diff --git a/code_of_conduct/coc-incident-resolution-procedures.md b/code_of_conduct/coc-incident-resolution-procedures.md new file mode 100644 index 000000000..8a5b351a7 --- /dev/null +++ b/code_of_conduct/coc-incident-resolution-procedures.md @@ -0,0 +1,248 @@ +# AsyncAPI Code of Conduct - Incident Resolution Procedures + +## Purpose and scope +These Procedures address the following topics related to the resolution of potential violations of the [AsyncAPI Code of Conduct](https://github.com/asyncapi/community/blob/master/CODE_OF_CONDUCT.md): + +- [How to submit a report](#how-to-submit-a-report) + - [Submit in writing](#submit-in-writing) + - [Submit in spoken conversation](#submit-in-spoken-conversation) + - [How to report anonymously](#how-to-report-anonymously) +- [What information to include in your report](#what-information-to-include-in-your-report) +- [What happens after a report is submitted](#what-happens-after-a-report-is-submitted) + - [Acknowledgement of Receipt](#acknowledgement-of-receipt) + - [Confirmation and Jurisdiction](#confirmation-and-jurisdiction) + - [Who will have access to reports](#who-will-have-access-to-reports) + - [Investigation](#investigation) + - [Notification to the Accused Person](#notification-to-the-accused-person) +- [Resolution](#resolution) + - [Interim Protective Measures](#interim-protective-measures) + - [Mediation and Resolution by Agreement](#mediation-and-resolution-by-agreement) + - [Potential Remedies](#potential-remedies) + - [Restorative Justice](#restorative-justice) + - [Transformative Justice](#transformative-justice) + - [Factors that the CoC Committee will consider](#factors-that-the-coc-committee-will-consider) + - [Examples of Remedies](#examples-of-remedies) + - [Accountability](#accountability) + - [Communicating the Results](#communicating-the-results) +- [Information Sharing](#information-sharing) +- [Confidentiality Policy](#confidentiality-policy) +- [No Retaliation](#no-retaliation) +- [Conflicts of Interest](#conflicts-of-interest) + - [Obligation to disclose potential conflicts of interest](#obligation-to-disclose-potential-conflicts-of-interest) + - [Procedures to disclose and confirm conflicts](#procedures-to-disclose-and-confirm-conflicts) + - [Procedures when a hard conflict of interest exists](#procedures-when-a-hard-conflict-of-interest-exists) + - [Procedures when a soft conflict of interest exists](#procedures-when-a-soft-conflict-of-interest-exists) +- [Amendments](#amendments) +- [Attribution](#attribution) + +## How to submit a report + +You may report a potential violation of the [AsyncAPI Code of Conduct](https://github.com/asyncapi/community/blob/master/CODE_OF_CONDUCT.md) in writing or in a spoken conversation as indicated below. + +### Submit in writing + +To report a violation in writing, please email [conduct@asyncapi.io](mailto:conduct@asyncapi.io), which goes to all primary (not alternate) members of the AsyncAPI Code of Conduct Committee (CoC Committee). If you do not want your report to be received by all members of the CoC Committee, either because you want to submit a report anonymously or because one of the CoC Committee members has a conflict of interest, you may send your report directly to any individual member of the CoC Committee. + +### Submit in spoken conversation + +If you prefer to report the violation in a spoken conversation, you may request a virtual meeting with a CoC Committee member. If the incident occurs at an event, you may report the incident in person either to a member of the AsyncAPI CoC Committee or a [Technical Steering Committee](https://www.asyncapi.com/community/tsc) (TSC) member. + + +### How to report anonymously + +If you desire to submit a report anonymously, please send a message directly to any individual member of our CoC Committee through the AsyncAPI Slack and let them know you would like to submit a Code of Conduct report anonymously. If you submit your report anonymously, that member of the CoC Committee will share the contents of your report with the rest of the CoC Committee. Still, they will not disclose your identity as the reporter to the other members of the CoC Committee (unless such disclosure is necessary to comply with applicable laws or court orders or to protect you or someone else from imminent danger). + +## What information to include in your report + +When reporting a potential Code of Conduct violation, please include the following information in your report: + +- Names of the people involved (or if names are unknown, use descriptions and any identifying information such as appearance, role, username, or handle), including the person you believe violated the Code of Conduct and any witnesses. + +- Description of the incident, including the events that occurred, the date and time, and the location or community space where the incident occurred. + +- The portion(s) of the CoC you believe to be violated. + +- If you have relevant documentary evidence, such as screenshots or photographs, please provide those with your report. + +## What happens after a report is submitted + +### Acknowledgement of Receipt + +The Code of Conduct Committee will acknowledge receipt of your report in a timely manner, usually within three business days. + +### Confirmation and Jurisdiction + +Once the report has been submitted, the AsyncAPI CoC Committee will confirm receipt of the report and, if it does not have jurisdiction over the incident, notify the complainants unless they have done so anonymously and have not provided their contact information. + +The Jurisdiction of the CoC Committee is as follows: +- [AsyncAPI Initiative GitHub](https://github.com/asyncapi) +- [AsyncAPI Slack](asyncapi.slack.com), including all external channels connected through [Slack Connect](https://slack.com/connect). +- AsyncAPI social networks: [Twitter](https://twitter.com/AsyncAPISpec), [LinkedIn](https://www.linkedin.com/company/asyncapi), [YouTube](https://www.youtube.com/asyncapi), [Twitch](https://www.twitch.tv/asyncapi), and [Mastodon](https://fosstodon.org/@AsyncAPISpec) +- AsyncAPI events: conferences, talks, workshops, etc. + +### Who will have access to reports + +Reports will only be shared with non-conflicted members of the CoC Committee, with very limited exceptions. See the “Confidentiality”, “Information Sharing”, “Communicating the Results”, and “Conflicts of Interest” sections below for more information. + +### Investigation + +The CoC Committee will investigate the report by reviewing available evidence and, if appropriate, interviewing witnesses, the accused person, and persons who were targeted or may have been harmed. In some cases, the CoC Committee may consult an external professional investigator or mediator to assist. + +If a potential incident comes to the CoC Committee’s attention that may present a serious continuing risk to community safety, the CoC Committee may investigate it even if no official report has been received. + +If the CoC Committee determines that the Code of Conduct was violated, the CoC Committee will decide on what remediation steps should be taken. See “Resolution” below for more information. + +### Notification to the Accused Person + +During or after the investigation, the CoC Committee shall notify the accused person that an incident report has been received concerning their alleged behavior unless it determines that the report is meritless or has been filed in bad faith. While the investigation is ongoing, the CoC Committee shall determine at its discretion whether, how, and when to notify the accused person, and how much information to share about the nature of the allegations, if any, taking into consideration risks of retaliation, evidence tampering or destruction, or witness tampering that might result from the notification. If the accused person was notified of the complaint before or during the investigation, after the incident is resolved, the CoC Committee shall notify the accused person of the outcome. + +## Resolution + +### Interim Protective Measures + +Although the CoC Committee will not take any permanent actions until the CoC Committee has gathered and reviewed all available evidence, the CoC Committee reserves the right to take immediate temporary action (e.g., temporarily suspending someone’s participation in a community space while the investigation is pending) at any time after learning of the incident if the CoC Committee determines this is necessary to protect the community or community members from the risk of harm. + +### Mediation and Resolution by Agreement + +If the accused person and the parties potentially harmed in an incident communicate to the CoC Committee that they would like to resolve the incident through restorative conversation (see “Restorative Justice" below), mediation, or mutual agreement, the CoC Committee will wait until the parties have attempted to do so before making any final decisions regarding resolution of the incident. If all involved parties consent, the CoC Committee, other community members, or an external professional mediator may help facilitate the discussion. If the involved parties agree on an outcome for resolving the incident, the CoC Committee will review the outcome to (a) determine if it is adequate or if any further actions need to be taken to protect the health and safety of the community and (b) support the involved parties with implementation and accountability. + +### Potential Remedies + +The goal of the Code of Conduct incident resolution is to support and safeguard the health, safety, and well-being of the community and individuals who participate and reinforce community standards for acceptable behavior; the purpose is not to punish. Whenever appropriate, the CoC Committee shall seek to resolve incidents using restorative justice and transformative justice approaches, as summarized below. + +#### Restorative Justice + +Restorative justice is a framework that seeks to repair the harm that was caused by an incident and focuses primarily on the parties directly involved in an incident. The goals of restorative justice are to: + +- Support the individuals harmed in their healing and recovery. + +- Provide the accused person with an opportunity to understand the impact of their actions, learn from their mistakes, and improve their behavior (e.g., through coaching, mentoring, or education). + +- Provide the accused person with opportunities to make amends and take actions that help repair or reduce the harm that was caused (e.g., through an apology or community service). + +Restorative justice typically involves a mediated conversation between the accused person and the person harmed to create shared understanding, healing, relationship repair, and closure. However, the CoC Committee will never require individuals involved in an incident to interact or communicate with each other; mediated conversations will only take place if all parties consent. + +#### Transformative Justice + +Transformative justice is a framework that seeks to address systemic issues that may have contributed to or encouraged the harmful behavior (e.g., systems or policies that reward bad behavior, or failure to educate newcomers about standards of conduct). If the CoC Committee determines there are any such systemic issues, the CoC Committee will recommend to the Technical Steering Committee that such issues be addressed, and, if appropriate, the CoC Committee may offer advice or other support. + +### Factors that the CoC Committee will consider + +If the CoC Committee determines that a violation has occurred, the CoC Committee will consider the following factors when determining what remediation steps to take: + +- Is the harmful behavior an isolated incident or pattern of repeated behavior? + +- How severe is the harmful behavior? + +- How does the harmful behavior impact the community and its participants? + +- What remedies would best repair or reduce the harm that was caused by the incident? + +- What remedies would best protect the community and involved individuals from further harm? + +- Is the accused person willing to acknowledge why their behavior was harmful and improve their behavior? If so, what remedies would best support them in improving their behavior? (e.g., education or mentoring) + +- Are there systemic issues that encourage and contribute to harmful behavior? If so, how can the community address these systemic issues to prevent similar incidents from occurring in the future? + +### Examples of Remedies + +The following are examples of remedies the CoC Committee may consider. The following list is non-exhaustive: + +- Issuing a warning + +- Removing harmful content from community or project spaces + +- A public or private apology + +- Temporary suspension or permanent ban from community or project + +- Temporary or permanent removal from leadership role + +- Education, mentoring, or coaching to help the accused improve their behavior + +- Addressing systemic issues that contributed to or encouraged the harmful behavior (e.g., through policy changes) to prevent similar incidents from occurring in the future + +### Accountability + +If any party does not fulfill their obligations related to the incident resolution (e.g., if the remediation requires the accused person to complete a non-violent communication course and fail to do so), the CoC Committee may take further action to resolve the incident. + +### Communicating the Results + +An incident is considered “resolved” when the CoC Committee has completed its investigation and either (a) determined what remediation actions are needed to resolve an incident (including determining that the involved parties’ agreed-upon resolution is adequate) (b) or determined that the CoC was not violated and no remediation is needed. When the incident is resolved, a member of the CoC Committee will inform the person who submitted the report. The CoC Committee will determine how much information to share with the reporter regarding the committee’s findings and what remediation steps were taken, if any, considering the privacy, confidentiality, and potential impact on the individuals involved in the incident. Notification to the accused person shall follow [Notification to the Accused Person](#notification-to-the-accused-person). The CoC Committee will also determine what information is necessary to share publicly or with community and project leaders. Any communication regarding the results of the investigation will be confidential. + +## Information Sharing + +The CoC Committee and Technical Steering Committee (TSC) may share information on an as-needed basis about reported incidents and their resolution for the limited purposes of: + +- Ensuring that the incident is resolved by the appropriate body with jurisdiction as described in the Jurisdiction and Escalation Policy, + +- Investigating and resolving the reported incident, + +- Maintaining a central repository of records and confirming whether an accused person has prior violations that were resolved by a different incident response team, as described in the Jurisdiction and Escalation Policy, + +- Implementing protective measures and protecting community members from harm, + +- Issuing public transparency reports regarding AsyncAPI Code of Conduct incidents (similar to [transparency reports issued by the Linux Foundation](https://www.linuxfoundation.org/blog/blog/linux-foundation-events-code-of-conduct-transparency-report-2021-event-summary/)). Such transparency reports will not disclose the identities of reporters, persons harmed, or witnesses. Depending on the resolution of an incident, the accused person might or might not be named in a transparency report or other communication to the community. + +## Confidentiality Policy + +When the AsyncAPI CoC Committee handles the incident response, only members of the CoC Committee without hard conflicts of interest (see our Conflicts of Interest policy below) will have access to confidential information about the incident, including the identities of the reporters. The AsyncAPI CoC Committee will not disclose the identities or confidential information provided by reporters or persons who were targeted or potentially harmed without their permission, except to a limited number of people on an as-needed basis for investigating and resolving the incident and protecting community members from harm. For example, the AsyncAPI CoC Committee might need to disclose certain information about the incident to TSC to arrange for onsite support for a target of harassment, or to an external professional mediator or investigator who is engaged to resolve the incident. Confidential information about incidents will only be shared with individuals who are obligated to similarly maintain the confidentiality of such information. + +In some cases, it may be necessary to question the accused person about the incident to perform a fair and thorough investigation of a reported incident. Although the CoC Committee will not disclose to the accused person who reported the incident or what witnesses have provided information, if only one person or a very small number of people were involved in or witnessed the incident, the accused person may be able to guess their identities. + +In rare situations, the CoC Committee may be required to disclose confidential information about an investigation to comply with applicable laws, a subpoena, or court order, or to defend against litigation. + +## No Retaliation + +The AsyncAPI community will not tolerate retaliation against community members who report concerns under the CoC in good faith or assist in an investigation as witnesses or by providing relevant information. Acts of retaliation are themselves violations of the AsyncAPI Code of Conduct. If you believe you have been retaliated against, please report it using the abovementioned reporting process. + +## Conflicts of Interest + +**Hard Conflicts**: A CoC Committee member has a hard conflict of interest if any of the following are true: + +- They are the accused person, or a person alleged to be directly harmed or targeted by the alleged wrongdoing; + +- They have a close personal relationship (e.g., close friend, spouse, or family member) with the accused person or with a person alleged to be directly targeted or harmed by alleged wrongdoing; + +- They have a close professional relationship (e.g., direct supervisory relationship at the same employer) with the accused person or with a person alleged to be directly harmed or targeted by the alleged wrongdoing; + +- They have another personal interest in the outcome of the incident that is likely to undermine their impartiality. + +- Multiple soft conflicts exist. + + +**Soft Conflicts**: A CoC Committee member has a soft conflict of interest if any of the following are true: + +- They work at the same company as the accused person, but do not have a close personal or professional relationship (e.g., they work for separate business units or divisions and do not interact regularly); + +- Other circumstances exist that are likely to give the appearance of a conflict of interest, even if such circumstances are not actually likely to undermine their impartiality, such as participating in public discussion about a potential violation or concern regarding the accused person’s behavior in their capacity rather than in their official capacity as representative of the CoC Committee. + +Merely witnessing a potential Code of Conduct violation does not constitute a conflict of interest. + +### Obligation to disclose potential conflicts of interest + +When a CoC Committee member has a potential soft or hard conflict of interest concerning a reported incident, they have an obligation to promptly disclose the nature of their potential conflict of interest to the rest of the CoC Committee (unless such potential conflict of interest is already known to the other members of the CoC Committee). + +### Procedures to disclose and confirm conflicts + +Statements of conflict and confirmation of stated conflicts must be done before initiating an investigation and recorded in the notes of the first meeting convened to discuss the incident. + +A committee member may verbally disclose a conflict statement to the committee first, then follow up in writing with the statement of conflict. They may also directly provide the statement of conflict in writing. + +Statements of conflict must include the kind of conflict (hard or soft) and the specific area of conflict. The committee is then required to confirm the conflict by the majority; for the existence of a soft conflict, the confirmation must also outline what that member can and can not do as part of the investigation. + +### Procedures when a hard conflict of interest exists + +A CoC Committee member with a hard conflict of interest will not be allowed to attend meetings or otherwise participate in discussions or decision-making of the CoC Committee related to the incident; their participation shall be limited to allowing the remaining CoC Committee members to interview them as a witness and providing information requested by the CoC Committee. Additionally, a CoC Committee Member with a hard conflict of interest will not be provided with confidential information about the incident (e.g., identities of reporters or contents of confidential reports). + +### Procedures when a soft conflict of interest exists + +A CoC Committee member with a soft conflict of interest will not have the right to vote but may be allowed to participate in a discussion regarding the incident. The remaining CoC Committee members will decide what information to provide such conflicted members and the extent to which such conflicted members may be present at meetings, participate in discussions, and otherwise assist in the resolution of the incident. Any decisions regarding the participation or recusal of a CoC Committee member with a soft conflict of interest will be recorded in the committee’s meeting minutes or other records. + +## Amendments + +The Code of Conduct Committee must approve any amendments to these Incident Resolution Procedures. + +## Attribution + +This document is based on the [CNCF Code of Conduct - Incident Resolution Procedures](https://github.com/cncf/foundation/blob/main/code-of-conduct/coc-incident-resolution-procedures.md). diff --git a/code_of_conduct/code-of-conduct-committee.md b/code_of_conduct/code-of-conduct-committee.md new file mode 100644 index 000000000..cbf82a4be --- /dev/null +++ b/code_of_conduct/code-of-conduct-committee.md @@ -0,0 +1,45 @@ +# AsyncAPI Code of Conduct Committee + +## Purpose + +The AsyncAPI Code of Conduct Committee (CoC Committee) is a committee that responds to investigates, and resolves [AsyncAPI Code of Conduct](https://github.com/asyncapi/community/blob/master/CODE_OF_CONDUCT.md) incidents. + +The members of the CoC Committee are members of the [Technical Steering Committee](https://www.asyncapi.com/community/tsc) (TSC) [voted](https://github.com/orgs/asyncapi/discussions/682#discussioncomment-7498209) publicly by the community. The committee has a two-year term, after which re-election will take place. + +## Members + +The AsyncAPI CoC Committee consists of 3 full members and 3 alternate members: + +**Full Members**: + +- [Aishat Muibudeen](https://github.com/mayaleeeee) +- [Azeez Elegbede](https://github.com/acethecreator) +- [Sergio Moya](https://github.com/smoya) + +**Alternate Members:** + +- [Alejandra Quetzalli](https://github.com/alequetzalli) +- [Thulisile Sibanda](https://github.com/thulieblack) + +If one of the CoC members listed above is unavailable or has to recuse themselves from participating in the resolution of a CoC incident due to a conflict of interest (see our [Conflict of Interest policy](*)), AsyncAPI may request assistance from the [Technical Steering Committee](https://www.asyncapi.com/community/tsc) in appointing an alternate from the TSC members to take their place for that incident. + +## How Decisions Are Made + +Decisions of the CoC Committee shall be made by consensus whenever possible. In the event consensus cannot be reached, decisions shall be made by majority vote of non-conflicted members of the CoC Committee. A decision to take temporary interim action in the event of an emergency may be taken by any individual CoC Committee member acting in good faith, and the CoC Committee shall review such action and decide whether to confirm or reverse such action. Any permanent action shall require approval of a majority of non-conflicted members of the CoC Committee. The CoC Committee may take action without a meeting if a majority of non-conflicted members express agreement in writing (e.g., email or Slack) and none of the non-conflicted CoC Committee members either object to the proposed action or request a meeting to discuss the proposed action within 24 hours after the action is first proposed to the CoC Committee. In the absence of such agreement in writing, the CoC Committee may only take action during or after a meeting takes place at which the proposed action is discussed and agreed to by consensus or voted upon by a quorum of the non-conflicted members. A majority of non-conflicted members shall be deemed a quorum for purposes of a meeting. See the [Conflict of Interest](*) section of the Incident Resolution Procedures for more information. + +## External Support Resources + +The CoC Committee may, in its discretion, consult external mediators, investigators, advisors, and consultants as needed to assist with resolution of CoC Incidents. Any such external resources shall not have a vote, and shall be required to maintain confidentiality. + +## Incident Resolution Procedures + +Please see our [Incident Resolution Procedures](coc-incident-resolution-procedures.md), which address, among others: + +- How to submit a report +- What information to share in your report +- What happens after a report is submitted +- Resolution +- Information sharing +- Confidentiality Policy +- No retaliation +- Conflicts of interest diff --git a/docs/donating-projects.md b/docs/donating-projects.md new file mode 100644 index 000000000..4a7e02e19 --- /dev/null +++ b/docs/donating-projects.md @@ -0,0 +1,49 @@ +## Donating Your Project + +Donating your open-source project to an open-source initiative involves transferring ownership or stewardship to an organization that supports and promotes open-source software. It ensures the project's sustainability, attracts more contributors, and aligns it with broader community goals. + +AsyncAPI initiative is open to receiving project donations that align with our goals and values. Before considering donating your project to the initiative, kindly visit our [AsyncAPI Roadmap](https://www.asyncapi.com/roadmap) to learn more about what we are looking at as a community in the near future. + +### Project Licensing + +Donating your project to an open-source organization like AsyncAPI can be exciting, hence why we need to ensure one of the most important parts of open-source projects, which is licensing. + +The AsyncAPI Initiative uses the [Apache-2.0 license](https://www.apache.org/licenses/LICENSE-2.0), which ensures our projects are open-source and community-driven. Before considering putting your project up for donation, ensure your project uses a compatible open-source license. + +### Legal Consideration + +All the projects under the AsyncAPI initiative are strictly community-driven. We've put legal consideration into donating projects to the initiative. + +- We value Contributor License Agreements (CLAs) as they provide project maintainers with the necessary legal rights to distribute and modify code contributed by different individuals, ensuring protection for both maintainers and contributors. + +- We make Intellectual Property (IP) Review essential when donating projects from organizations instead of individual contributors. It's crucial to verify ownership and the chain of title to ensure that no proprietary code or third-party IP is included, maintaining a clear and respectful process for all involved. + +### Community Engagement + +When donating your project to a community-driven initiative like AsyncAPI, you should understand that communication is an integral part of the initiative. Before donating your project, communication with the community has to be established. + +Follow the instructions below to establish and involve the community in your project donation: + +1. Visit [AsyncAPI Initiative Discussions](https://github.com/orgs/asyncapi/discussions). +2. Create a new discussion by clicking on `New discussion` and selecting the `Idea` category. Specify in the _title_ that you want to donate to an existing project. In the _description_, state the purpose of the new repository and why it should be part of the AsyncAPI organization. Here's a [sample discussion about donating an existing project](https://github.com/orgs/asyncapi/discussions/643). +3. Start a discussion with community members to discuss the project idea, specify if you want to use AsyncAPI CI/CD workflows, and volunteer to become a maintainer for that project. For better visibility, share the discussion in the `#general` channel on our Slack. +4. Answer questions from contributors and maintainers about your project. Ask relevant questions about your project donation. + +### Project Migration + +After a successful community engagement, we move on to the final phase of project migration. Establish a successful project migration via the following steps: + +1. Visit the [AsyncAPI Community Repo](https://github.com/asyncapi/community) and open a [new issue](https://github.com/asyncapi/community/issues/new?assignees=&labels=enhancement&projects=&template=enhancement.yml&title=%5BFEATURE%5D+%3Cdescription%3E). +2. Write your project's details and include a summary of the community discussion for your project. +3. Tag the `@asyncapi/tsc_members` at the end of the proposal description and ask for a vote on migrating your project to the organization, because the Technical Steering Committee (TSC) must approve the project donation. Tagging TSC members notifies them to vote on the proposed project. +4. If the TSC approves the new repository, then either `@derberg` or `@fmvilas` complete the project migration to the AsyncAPI organization. +5. Configure the CI pipelines to match the initiative's standards, so that either `@derberg` or `@fmvilas`can run AsyncAPI CI/CD workflows that push basic GitHub Actions workflows to the newly donated project. +6. New maintainers are invited as repo admins. + +### Post Donation Maintenance + +Successfully donating a project doesn't mean the end of your journey with it. On the contrary, the post-donation phase is crucial for the sustained health and growth of the project. Ensure your project continues to thrive and benefits the community long after donation by implementing these key practices: + +- **Ongoing Contributions**: Your involvement shouldn't stop with the donation. Continue actively contributing to the project by adding new features, refining existing functionalities, and fixing bugs. Demonstrating ongoing commitment encourages others to contribute as well. +- **Documentation Updates**: Keep the project's documentation up-to-date. Write documentation for installation, configuration, usage, and API reference materials. As the project evolves, it's essential that the documentation reflects these changes accurately to assist both new and existing users. +- **Community Support**: Engage with the community by offering support, answering questions, providing feedback on user suggestions, and addressing any concerns. A vibrant, supportive community is key to a project's sustainability. diff --git a/docs/onboarding-guide/contribute-to-docs.md b/docs/onboarding-guide/contribute-to-docs.md new file mode 100644 index 000000000..092fd477e --- /dev/null +++ b/docs/onboarding-guide/contribute-to-docs.md @@ -0,0 +1,12 @@ +--- +title: Contribute to docs +weight: 70 +--- + +## Contribute to docs + +There are several ways to request your first AsyncAPI docs task: + +1. **Connect with a docs maintainer:** Ask for a `good-first-issue` in the `#13_docs` channel of the [AsyncAPI Slack](https://www.asyncapi.com/slack-invite) workspace. +2. **Update current docs:** Surf the existing documentation, look for `typos`, `grammar`, `errors`, create an issue, and submit a Pull Request. +3. **Propose new docs:** If you have any ideas or suggestions for necessary documentation, [create a new docs issue](https://github.com/asyncapi/website/issues/new?labels=%F0%9F%93%91+docs&projects=&template=docs.yml&title=%5B%F0%9F%93%91+Docs%5D%3A+) and propose yourself as the assignee. diff --git a/docs/onboarding-guide/create-new-docs-directories.md b/docs/onboarding-guide/create-new-docs-directories.md new file mode 100644 index 000000000..e935c2587 --- /dev/null +++ b/docs/onboarding-guide/create-new-docs-directories.md @@ -0,0 +1,24 @@ +--- +title : 'Create new docs directories' +weight : 80 +--- + +### Create new docs directories +Create a new docs directory (folder) via the following steps: +1. Identify the content bucket under which your document falls. +2. Open the project locally in your code editor of choice and navigate to the parent folder. +3. Right-click on the parent folder and click "new folder". +4. Give an appropriate name to the new folder. +5. Add the following two files to the new folder: + 1. `index.md`: Used as the main content for a website's directory or specific webpage. It's named index because many web servers are configured to automatically look for an index file when accessing a directory. When you access a directory on a web server, if an `index.md` file is present, it will be displayed as the default page for that directory. + 2. `_section.md`: Used for reusable components or partial content within a website's structure. It defines the page's `title` and `weight`. The title defines a human-readable title, and weight controls the order in which sections (directories) are displayed. +6. You can edit the index page after successfully creating these pages. + +```mermaid +flowchart LR + A[parent Folder] --> B[new Folder] + B[new Folder] --> C[index.md] + B[new Folder] --> D[_section.md] + B[new Folder] --> E[example-doc-1.md] + B[new Folder] --> F[example-doc-2.md] +``` diff --git a/docs/onboarding-guide/open-docs-pull-request.md b/docs/onboarding-guide/open-docs-pull-request.md new file mode 100644 index 000000000..b426fc704 --- /dev/null +++ b/docs/onboarding-guide/open-docs-pull-request.md @@ -0,0 +1,15 @@ +--- +title : 'Create new docs pull request' +weight : 90 +--- + +## Create a new docs pull request +Create and submit a docs pull request (PR) via the following steps: + +- A Docs’ PR should solve one documentation problem. +- If there is no current issue for the docs task you want to accomplish, please open a docs issue before creating a PR. +- Use the [conventional commit style](https://github.com/asyncapi/.github/blob/master/CONTRIBUTING.md#conventional-commits) when creating PRs. Always create a docs issue or PR with the `docs:` prefix in the title. +- Please check your contribution and ensure it follows the AsyncAPI style guide. +- Tag other technical writers to review your document. +- Tag an engineer or subject matter expert (SME) to review the technical details. +- After implementing all the feedback you requested, please update your PR and wait for further feedback before it can be merged. diff --git a/docs/onboarding-guide/tools-and-setup.md b/docs/onboarding-guide/tools-and-setup.md new file mode 100644 index 000000000..24bc37454 --- /dev/null +++ b/docs/onboarding-guide/tools-and-setup.md @@ -0,0 +1,46 @@ +--- +title: Tools and setup +weight: 60 +--- + +## Tools for technical writers + +Technical writer contributors need the following tools to contribute to AsyncAPI documentation effectively: + +- A laptop or desktop computer capable of running the tools necessary to contribute to the project. +- Stable internet access to clone the project repository, submit contributions, and stay updated on project changes. +- A [GitHub](https://github.com) account. AsyncAPI hosts all its project's source code and documentation on GitHub. You'll need a GitHub account to create issues, fork the repository, submit pull requests, and more. If you're new to GitHub, familiarize yourself with [basic GitHub functionalities and workflows](https://docs.github.com/en/get-started). +- A code editor, such as [VS Code](https://code.visualstudio.com), capable of handling Markdown files. +- [Git](https://git-scm.com), a version control system. + +## Setup your AsyncAPI local environment +1. Fork the repository by clicking the `Fork` option on the top right of the main repository. + +2. Open Command Prompt on your local computer. + +3. Clone the forked repository by adding your GitHub username instead of ``. + For multiple contributions, follow the [proper configuration of a forked AsyncAPI repo](https://github.com/asyncapi/community/blob/master/git-workflow.md). + +```bash + git clone https://github.com//website/ +``` + +4. Navigate to the website directory. + +```bash + cd website +``` + +5. Install all website dependencies. + +```bash + npm install +``` + +6. Run the website locally. + +```bash + npm run dev +``` + +7. Access the live development server at [localhost:3000](http://localhost:3000). diff --git a/mentorship/asyncapi-mentorship/README.md b/mentorship/asyncapi-mentorship/README.md index e5aabd0e0..f40873eca 100644 --- a/mentorship/asyncapi-mentorship/README.md +++ b/mentorship/asyncapi-mentorship/README.md @@ -5,7 +5,7 @@ The AsyncAPI Mentorship makes it easy to sponsor and help train the next generat ## Program Cycles and Archive data | Year | Term | Status | Announcement | Details | | ---- | ------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | -| 2023 | Jan-Nov | In progress | | [Jan-Nov](2023/README.md) | +| 2023 | Jan-Nov | Completed | | [Jan-Nov](2023/README.md) | | 2022 | Jan-Nov | Completed | | [Jan-Nov](2022/README.md) | ## Current cycle @@ -134,4 +134,4 @@ AsyncAPI is not required to pay any stipends to any Participant that violates an ## References -This document was adapted from the [GSOC Guidlines and Rules](https://summerofcode.withgoogle.com/rules). \ No newline at end of file +This document was adapted from the [GSOC Guidelines and Rules](https://summerofcode.withgoogle.com/rules). diff --git a/mentorship/summerofcode/2023/README.md b/mentorship/summerofcode/2023/README.md new file mode 100644 index 000000000..8c589b66b --- /dev/null +++ b/mentorship/summerofcode/2023/README.md @@ -0,0 +1,155 @@ +# Status: Completed +The summary of the program can be found at https://github.com/orgs/asyncapi/discussions/997 + +## Timeline + +- January 23: Organization applications open +- February 7: Accepted GSoC Organizations announced +- February 22 - March 20: Potential GSoC contributors discuss application ideas with mentoring organizations +- March 20 - April 4: GSoC contributor application period +- May 17 - June 7: Accepted GSoC Contributor projects announced +- May 29: Contributors work on their Google Summer of Code projects +- August 28 - September 4: Mentors submit final GSoC contributor evaluations (standard coding period) +- September 5: Initial results of Google Summer of Code 2023 announced + +## Accepted Project Ideas +| No | Project Idea | Mentor/s | Category | Mentee/s | +| --- | --- | --- | --- | --- | +| 1 | [Authentication and Authorization support for websocket adapters: Glee](https://github.com/asyncapi/glee) | @Souvikns @KhudaDad414 | Engineering | @oviecodes | +| 2 | [Automate listing of members of technical steering committee: Community](https://github.com/asyncapi/community) | @derberg | Engineering | @14Richa | +| 3 | [Introduce UI tests and refactoring in the website: Website](https://github.com/asyncapi/website) | @akshatnema @imabp | Engineering | @reachaadrika | +| 4 | [Add "Autofix" feature for common linting errors (w/ spectral): Vs-code Extension](https://github.com/asyncapi/vs-asyncapi-preview) | @ivangsa | Engineering | @Savio629 | + + +## Proposed Project Ideas + + +## 1) Authentication and Authorization support for websocket adapters: Glee + +In particular, Glee allows users to create WebSocket servers, which necessitates the implementation of secure and reliable authentication and authorization mechanisms. This ensures that only authorized parties can access and use the WebSocket servers, thereby enhancing the overall security and privacy of the communication channels. + +**Mentors**: +@Souvikns @KhudaDad414 + +**Project Repo** + +[https://github.com/asyncapi/glee](https://github.com/asyncapi/glee) + + +**Expected Difficulty**: +Easy-Medium + +**Expected Time Commitment**: +175 Hour + +**Technical skills requried** + +Typescript, nodejs, websocket, EDA basics + + +## 2) Automate listing of members of technical steering committee: Community + +Our [open governance model](https://github.com/asyncapi/.github/blob/master/CHARTER.md) introduces a TSC that consists of all the CODEOWNERS that want to use their right to have a vote in TSC decisions making process. + +We need a bot/github action that will read VOTERS files from all repos, maintain single list, and put it on the website + +Description +get a github action that reacts on any push to master and checkes if voters file was edited. Then reads it and add/remove/modify a voter in the list stored on the website +get a github action that on a PR level validates modification in VOTERS file and blocks PR in case VOTERS cannot be added to TSC list as they are affiliated with the company that already reached the limit of representation +decide on structure of VOTERS file +get a mechanism that collects more details about TSC members (social accounts, hire availability, etc) + +Learn more here https://github.com/asyncapi/.github/issues/210 + +**Mentors**: +@derberg @KhudaDad414 + +**Project Repo:** +https://github.com/asyncapi/.github + +**Expected Difficulty**: +Easy-Medium + +**Expected Time Commitment**: +175 Hour + +## 3) Introduce UI tests and refactoring in the website: Website + +We need automation tests to run on the PR level which checks the overall build and codebase of the changes made in the PR. It should cover all the aspects of testing the website and the scripts running inside it. The idea of this project is not only to add UI tests, but also to refactor some parts in code to effectively create tests on it. + +What are UI tests? +User Interface testing, also known as UI testing or GUI testing, tests the application’s visual elements to validate proper functionality and expected performance. It ensures that UI functions and application components have no defects, such as icons, radio buttons, text boxes, toolbars, color, fonts, checkboxes, windows, and menus. The primary aspects of UI testing are functionality, performance, usability, compliance, and visual design of the software application to make sure the application works successfully and satisfactorily. + +Why do we need this? +We do need these tests because of following reasons: + +- we have no tests to test the components and the functions inside it. +- more and more scripts are added to the repository +- no tests, means nothing forces us to write clearer and testable small functions. +- soon website maintenance/contribution will become hard as more and more addition of code will make Duplication and inconsistency inside the codebase. + + +Learn more here https://github.com/asyncapi/website/issues/1090 + +**Mentors**: +@akshatnema +@imabp + +**Project Repo:** +https://github.com/asyncapi/website + +**Expected Difficulty**: +Easy-Medium + +**Expected Time Commitment**: +175 Hour + + +## 4) Add "Autofix" feature for common linting errors (w/ spectral): Vs-code Extension + +AsyncAPI-Preview + Spectral for VSCode form a perfect combo in terms of UX/DX for asyncapi editing: + +with this extension, you can navigate and preview your API definition +while Spectral for VSCode provides inline and listed linting error for common and even custom mistakes +VSCode comes with an API for providing quick/autofixes for linting errors (see https://code.visualstudio.com/docs/editor/refactoring https://code.visualstudio.com/api/references/vscode-api#CodeActionProvider and https://github.com/microsoft/vscode-extension-samples/tree/main/code-actions-sample for an example) + +The purpose of this feature is to provide auto-fix refactoring for the most common and standard spectral linting errors for asyncapi: +https://docs.stoplight.io/docs/spectral/1e63ffd0220f3-async-api-rules + +Learn more here https://github.com/asyncapi/vs-asyncapi-preview/issues/160 + +**Mentors**: +@ivangsa + +**Project Repo:** +https://github.com/asyncapi/vs-asyncapi-preview + +**Expected Difficulty**: +Easy-Medium + +**Expected Time Commitment**: +175 Hour + +## 5) AsyncAPI: Add help/{command} endpoint: Server API + +Suggested by Marc DiPasquale in Slack comment https://asyncapi.slack.com/archives/CQVJXFNQL/p1662141074739369?thread_ts=1661395911.924239&cid=CQVJXFNQL + +We should create such an endpoint `help/{command}` to return instruction of given command to the user. For example `help/generate` should return available parameters such an available templates etc. + +`help/{command}` is just a suggestion, we can go with other endpoint(s). + +Also, what is very important, that endpoint should be done in a similar way as in our main CLI - https://github.com/asyncapi/cli#usage, so main help endpoint should return all available endpoints and particular one like `help/generate` should return details about given command. + +Learn more here https://github.com/asyncapi/server-api/issues/144 + +**Mentors**: +@BOLT04 + +**Project Repo:** +https://github.com/asyncapi/server-api + +**Expected Difficulty**: +Easy-Medium + +**Expected Time Commitment**: +175 Hour diff --git a/mentorship/summerofcode/2024/README.md b/mentorship/summerofcode/2024/README.md new file mode 100644 index 000000000..b6e476c30 --- /dev/null +++ b/mentorship/summerofcode/2024/README.md @@ -0,0 +1,33 @@ +# Status: In Progress + +## Timeline + +- January 22: Organization applications open +- February 21: Accepted GSoC Organizations announced +- February 22 - March 18: Potential GSoC contributors discuss application ideas with mentoring organizations +- March 18: The GSoC contributor application period begins +- April 02: Proposal Deadline +- May 1: Accepted GSoC Contributor projects announced +- May 1 - 26: Community Bonding Period | GSoC contributors get to know mentors, read documentation, get up to speed to begin working on their projects +- May 27: Coding officially begins! +- July 8: Mentors and GSoC contributors can begin submitting midterm evaluations +- July 12: Midterm evaluation deadline (standard coding period) +- July 12 - August 19: Work Period | GSoC contributors work on their project with guidance from Mentors +- August 19 - 26: Final week: GSoC contributors submit their final work product and their final mentor evaluation (standard coding period) +- August 26 - September 2: Mentors submit final GSoC contributor evaluations (standard coding period) +- September 3: Initial results of Google Summer of Code 2024 announced +- September 3 - November 4: GSoC contributors with extended timelines continue coding +- November 4: Final date for all GSoC contributors to submit their final work product and final evaluation +- November 11: Final date for mentors to submit evaluations for GSoC contributor projects with extended deadlines + + +## Accepted Project Ideas +| No | Project Idea | Mentor/s | Category | Mentee/s | +| --- | --- | --- | --- | --- | +| 1 | [Autofix for Spectral Linting Errors: VS Code Extension](https://github.com/asyncapi/vs-asyncapi-preview/issues/160) | [Pavel Bodiachevskii](https://github.com/Pakisan) | Engineering | [Esther Xiao](https://github.com/FelicixAwe) | +| 2 | [Script Stability Enhancement for AsyncAPI Website](https://github.com/asyncapi/website/issues/2626) | [Sambhav Gupta](https://github.com/sambhavgupta0705), [Ansh Goyal](https://github.com/anshgoyalevil) | Engineering | [Vishvamsinh Vaghela](https://github.com/vishvamsinh28) | +| 3 | [AsyncAPI Generator Maintainership](https://github.com/asyncapi/generator/issues/1145) | [Lukasz Gornicki](https://github.com/derberg) | Engineering | [Mintu Gogoi](https://github.com/Gmin2), [Yuan Yuan](https://github.com/lmgyuan) | +| 4 | [Markdown and MermaidJS Diagrams Preview: VS Code Extension](https://github.com/asyncapi/vs-asyncapi-preview/issues/161) | [Iván García Sainz-Aja](https://github.com/ivangsa), [Azeez Elegbede](https://github.com/acethecreator) | Engineering | [NIKHIL CHAUDHARI](https://github.com/nikhil-3112) | +| 5 | [AsyncAPI Website UI Kit Development](https://github.com/asyncapi-archived-repos/design-system/issues/4) | [Azeez Elegbede](https://github.com/acethecreator), [Akshat Nema](https://github.com/akshatnema) | Engineering | [Ashmit JaiSarita Gupta](https://github.com/devilkiller-ag) | +| 6 | [Dynamic Open Graph Preview for AsyncAPI Studio](https://github.com/asyncapi/studio/issues/224) | [Sergio Moya](https://github.com/smoya) | Engineering | [Ankit Dash](https://github.com/helios2003) | +| 7 | [Conference Website Maintainance](https://github.com/asyncapi/conference-website/issues/284) | [Azeez Elegbede](https://github.com/acethecreator), [Aishat Muibudeen](https://github.com/mayaleeeee), [Thulisile Sibanda](https://github.com/thulieblack) | Engineering | [Ashmit Jagtap](https://github.com/ashmit-coder) | diff --git a/mentorship/summerofcode/2024/asyncapi-gsoc-ideas-page.md b/mentorship/summerofcode/2024/asyncapi-gsoc-ideas-page.md new file mode 100644 index 000000000..e1bd5c717 --- /dev/null +++ b/mentorship/summerofcode/2024/asyncapi-gsoc-ideas-page.md @@ -0,0 +1,84 @@ +# AsyncAPI Ideas Page: Google Summer of Code 2024 +Welcome to the **AsyncAPI Ideas Page** with our proposed projects for Google Summer of Code (GSoC) 2024! If you are an interested student/contributor, please don't hesitate to contact our mentors directly to discuss project ideas. + +## 1) [Autofix for Spectral Linting Errors: VS Code Extension](https://github.com/asyncapi/vs-asyncapi-preview/issues/160) +Enhance the [AsyncAPI Preview + Spectral](https://github.com/asyncapi/vs-asyncapi-preview) VS Code extension by introducing an autofix feature. This improvement aims to streamline the editing experience by automatically resolving common Spectral linting errors directly within the IDE. + +- 🎯 **Outcome:** Automate corrections for standard spectral linting issues in AsyncAPI documents. [Learn more](https://docs.stoplight.io/docs/spectral/1e63ffd0220f3-async-api-rules). +- 🛠️ **Skills Required:** TypeScript/JavaScript and understanding of Spectral rules. +- 🧩 **Difficulty:** Easy/Medium +- 👩🏿‍🏫 **Mentor(s):** [@ivangsa](https://github.com/ivangsa) +- ⏳ **Length:** 175 Hours + +## 2) [Script Stability Enhancement for AsyncAPI Website](https://github.com/asyncapi/website/issues/2626) +Improve the [AsyncAPI website](https://github.com/asyncapi/website)'s robustness by enhancing script stability in the `/scripts/*` directory. This project involves selecting a suitable testing framework for JavaScript and Next.js, integrating it with the website, developing detailed test cases for scripts, and setting up a GitHub Actions CI workflow for automated testing. + +- 🎯 **Outcome:** Achieve a stable website framework to support continuous development and updates. +- 🛠️ **Skills:** JavaScript, Next.js, unit testing, and CI/CD practices. +- 🧩 **Difficulty:** Medium/Hard +- 👩🏿‍🏫 **Mentor(s):** [@sambhavgupta0705](https://github.com/sambhavgupta0705), [@anshgoyalevil](https://github.com/anshgoyalevil) +- ⏳ **Length:** 350 Hours + +## 3) [AsyncAPI Generator Maintainership](https://github.com/asyncapi/generator/issues/1145) +This initiative aims to guide you on a journey from being a contributor to becoming a maintainer of the project. You'll gain insight into the responsibilities of a maintainer, involving tasks beyond mere coding. + +- 🎯 **Outcome:** Taking responsibility for the project's future and continuous improvement. +- 🛠️ **Skills:** JavaScript/TypeScript, testing libraries, Docker, virtualization, and test automation. +- 🧩 **Difficulty:** Medium/Hard +- 👩🏿‍🏫 **Mentor(s):** [@derberg](https://github.com/derberg) +- ⏳ **Length:** 350 Hours + +## 4) [Markdown and MermaidJS Diagrams Preview: VS Code Extension](https://github.com/asyncapi/vs-asyncapi-preview/issues/161) +Upgrade the [AsyncAPI Preview](https://github.com/asyncapi/vs-asyncapi-preview) VS Code extension to include a feature for visualizing message payloads through Markdown and MermaidJS Class Diagrams. It also incorporates an export feature for the Markdown preview to facilitate its use in external documentation. This enhancement will work with both AsyncAPI schemas and Avro (.avsc) files to offer a dynamic and interactive view of message structures. + +- 🎯 **Outcome:** Deliver an enriched AsyncAPI preview tool that provides a user-friendly, graphical representation of message payloads, improving comprehension and documentation within the AsyncAPI ecosystem. +- 🛠️ **Skills:** TypeScript/JavaScript, MermaidJS, and AsyncAPI schemas. +- 🧩 **Difficulty:** Easy/Medium +- 👩🏿‍🏫 **Mentor(s):** [@ivangsa](https://github.com/ivangsa) +- ⏳ **Length:** 175 Hours + +## 5) [AsyncAPI Website UI Kit Development](https://github.com/asyncapi-archived-repos/design-system/issues/4) +Create a UI Kit for the AsyncAPI website to ensure brand visual consistency and streamline web development. The project will leverage Tailwind CSS, focusing on component-based class encapsulation to minimize class duplication and promote a modular, easy-to-maintain design system. + +- 🎯 **Outcome:** Establish an AsyncAPI Website UI Kit that aligns with our design principles, facilitating the creation of uniform and manageable website elements. +- 🛠️ **Skills:** JavaScript, React, Storybook, and TailwindCSS. +- 🧩 **Difficulty:** Easy/Medium +- 👩🏿‍🏫 **Mentor(s):** [@acethecreator](https://github.com/acethecreator), [@akshatnema](https://github.com/akshatnema) +- ⏳ **Length:** 350 Hours + +## 6) [Dynamic Open Graph Preview for AsyncAPI Studio](https://github.com/asyncapi/studio/issues/224) +Improve social sharing for [AsyncAPI Studio](https://studio.asyncapi.com/) by implementing a dynamic Open Graph link preview generator. This feature will create context-specific preview images for shared links, incorporating key details like the title, description, and statistics from the shared AsyncAPI document. + +- 🎯 **Outcome:** Provide a richer, more informative link-sharing experience on platforms like Twitter, LinkedIn, Facebook, and Slack with custom preview images. +- 🛠️ **Skills:** TypeScript/JavaScript and React. +- 🧩 **Difficulty:** Easy/Medium +- 👩🏿‍🏫 **Mentor(s):** [@smoya](https://github.com/smoya) +- ⏳ **Length:** 175 Hours + +## 7) [Conference Website Maintainance](https://github.com/asyncapi/conference-website/issues/284) +Ensure our conference website remains a dynamic and user-friendly for the upcoming 2024 AsyncAPI Conference. + +- 🎯 **Outcome:** Improve the website's efficiency and user-friendliness for an improved user experience. +- 🛠️ **Skills:** JavaScript, Tailwind, and any testing framework. +- 🧩 **Difficulty:** Easy/Medium +- 👩🏿‍🏫 **Mentor(s):** [@acethecreator](https://github.com/acethecreator) [@mayaleeeee](https://github.com/Mayaleeeee) [@thulieblack](https://github.com/thulieblack) +- ⏳ **Length:** 350 Hours + +## Contact AsyncAPI Mentors +- Join [our Slack workspace](https://www.asyncapi.com/slack-invite). Observe our [Slack etiquette](https://github.com/asyncapi/.github/blob/master/slack-etiquette.md) and [AsyncAPI code of conduct](https://github.com/asyncapi/.github/blob/master/CODE_OF_CONDUCT.md). +- Join the dedicated Mentorship channel `#09_mentorships` to meet all other GSoC mentees and mentors. + +## FAQ +1. **How active are previous GSoC contributors in AsyncAPI?** + Although AsyncAPI hasn't directly participated in GSoC, our projects were featured in Postman's proposal last year. Active contributors from that cohort include: + - **[@14Richa](https://github.com/14Richa)** in our [.github](https://github.com/asyncapi/.github), [community](https://github.com/asyncapi/community), and [optimizer](https://github.com/asyncapi/optimizer) repositories. + - **[@reachaadrika](https://github.com/reachaadrika)** in our [AsyncAPI website](https://github.com/asyncapi/website) repository. + - **[@oviecodes](https://github.com/oviecodes)** in our [Glee](https://github.com/asyncapi/glee) and [parser-js](https://github.com/asyncapi/parser-js) repositories. + +2. **Is using ChatGPT for GSoC project proposals allowed?** + We advise against using ChatGPT or similar AI tools for your GSoC project proposals with AsyncAPI. Should you choose to use such tools, we require that this be fully disclosed in your application. + +3. **Where is the AsyncAPI source code located?** + You can find all AsyncAPI source code on GitHub under our organization: [https://github.com/asyncapi](https://github.com/asyncapi). + +>If you have further questions or queries, please create an issue in this `/community` repo (with the prefix `GSoC 2024`) or start an [open AsyncAPI discussion](https://github.com/orgs/asyncapi/discussions). diff --git a/mentorship/summerofcode/README.md b/mentorship/summerofcode/README.md new file mode 100644 index 000000000..34242bf01 --- /dev/null +++ b/mentorship/summerofcode/README.md @@ -0,0 +1,43 @@ +# Google Summer of Code - Getting Started + +###### Introduction + +Google Summer of Code (GSoC) is an annual program sponsored by Google that offers stipends to contributors for working on open-source projects during the summer. Contributors gain real-world software development experience by working with mentors from participating organizations. The goal is to encourage developers to contribute to open-source projects and improve their coding skills. If you want to develop open-source software, this program is for you! + +AsyncAPI is looking for contributors who are eager to learn, have good coding abilities, and, most importantly, have a strong passion for APIs and open-source development. + + +### Requirement + +Successful GSoC contributors will receive [compensation](https://developers.google.com/open-source/gsoc/help/student-stipends) for their contributions. + +To be eligible as a contributor, you must be at least 18 years old at the time of registration and be new to open-source projects. Group applications are not permitted. + +Please verify your eligibility by visiting the [Google Summer of Code (GSoC) website.](https://summerofcode.withgoogle.com/get-started) + +TL;DR: GSoC exclusively focuses on coding projects. While initiatives like documentation or design are valuable, they are not permitted within the scope of GSoC. You can check out the AsyncAPI Mentorship Program or GSoD for other noncoding-related projects. + +### First Steps + +- **The ideal starting point is [Google's Student Guide](https://google.github.io/gsocguides/student)**! + Carefully read through the guide to familiarize yourself with the initiative. The guide provides a comprehensive program overview and offers valuable advice on starting communication, proposal writing, and beginning your work. Additionally, [refer to Google's FAQ](https://developers.google.com/open-source/gsoc/faq) for more information. + +- **Get familiar with the AsyncAPI project.** + Please be sure to familiarize yourself with the AsyncAPI initiative and its mission and [get involved in the community](https://asyncapi.com/slack-invite). Explore the [AsyncAPI projects](https://github.com/asyncapi), get an idea of the project of your interest, and explore the source code and organization of the project. + +- **Write your project proposal.** + Visit the [ideas page](https://github.com/asyncapi/community/blob/master/mentorship/summerofcode/2024/asyncapi-gsoc-ideas-page.md) to choose a topic that catches your interest. You can also draw inspiration from projects from [previous years](https://github.com/asyncapi/community/tree/master/mentorship/summerofcode). + + We recommend reading [Google's guide for writing a proposal](https://google.github.io/gsocguides/student/writing-a-proposal). + + For feedback, submit your work early! However, due to the influx of applications, feedback may only be available during the final week after the deadline. + +### Getting Started with AsyncAPI +- New to AsyncAPI? Visit the [AsyncAPI website](asyncapi.com) to learn more about the initiative. +- Visit the [Community section](https://www.asyncapi.com/community) of the website to learn about the community behind AsyncAPI. +- Explore all the active projects in the organization by visiting our [GitHub org](https://github.com/asyncapi). +- Consider tackling one of the good first issues, resolving a bug, or enhancing existing features by visiting our [Issues Dashboard](https://www.asyncapi.com/community/dashboard). Include links to your past contributions to AsyncAPI in your proposal. Stay calm! If you're new to navigating a large codebase, we are here to help you 😊. + +### Thanks! + + We appreciate your interest in choosing AsyncAPI for your Google Summer of Code project! diff --git a/mentorship/summerofcode/application-template.md b/mentorship/summerofcode/application-template.md new file mode 100644 index 000000000..c8c5ac500 --- /dev/null +++ b/mentorship/summerofcode/application-template.md @@ -0,0 +1,45 @@ +# GSoC Application Template + +This is the AsyncAPI Project's Google Summer of Code Application Template. We made it to assist contributors in crafting impressive proposals that will impress us. You can submit a draft proposal early to get feedback and iterate early. Be sure to read [Google's guide to writing a proposal](https://google.github.io/gsocguides/student/writing-a-proposal) + +Here's what we want to hear from you: + +### Contact information + +Please provide your most basic contact information, such as: +- Full name +- Email address +- GitHub handle +- Contact Number(include your country code) + +### Project Information + +This section is for you to provide all your understanding of the project, such as: +- What is the aim of your project, and what problem does it aim to address? +- Providing a detailed description of the proposed project. Here's where to add technical explanations, architectural diagrams, or design mockups. +- What will the outcome of your project be at the end of the program? +- How do you plan to finish the project on schedule? For instance, what are the important milestones, and what is your approximate timeline for reaching them? +- What qualities should a suitable mentor for your project possess? +- What are your plans for the project after completion? + +### Your Understanding of AsyncAPI + +AsyncAPI is an initiative with many projects and design patterns. In this section, we assess your familiarity with AsyncAPI. We encourage seasoned users and newcomers to explore and understand AsyncAPI during the application phase. + +- Please share your background as an AsyncAPI user or contributor, or if you're new to AsyncAPI, outline your intentions for learning AsyncAPI. +- If you've submitted bug fixes or patches to any of our projects before, please provide links to the repositories for one or more examples of your work with AsyncAPI. +- Please explain your knowledge of the AsyncAPI development infrastructure and Git(a plus if it's for your chosen project). If you're unfamiliar with them, what do you plan to learn? We'd like to encourage you to use the application period to familiarize yourself with these tools. +- Include or share links to a sample of code unrelated to AsyncAPI demonstrating your development abilities(Optional). + +### Your Involvement with the AsyncAPI community + +We welcome applications from folks new to AsyncAPI. If you have previous experience with the AsyncAPI community, please share it. We encourage newcomers to use this application period to get involved with the AsyncAPI community. + +- How long have you been engaged with the AsyncAPI community? For instance, have you attended community meetings, contributed to the website, or participated in AsyncAPI events in any capacity? +- Have you developed and released any project or offered support or services (voluntary or commercial) to AsyncAPI users independently from the official AsyncAPI project? +- If you have not engaged with the AsyncAPI community, what are your plans for getting involved? +- What are your intentions for contributing to AsyncAPI besides your project work? Do you anticipate continuing your involvement with AsyncAPI after finishing your project? If yes, how do you plan to do so? + +### Bio + +Share a bit about yourself. What are you studying and where? What activities do you enjoy? Why are you the right person for this project? diff --git a/mentorship/summerofcode/mentors-guideline.md b/mentorship/summerofcode/mentors-guideline.md new file mode 100644 index 000000000..c8b610d7b --- /dev/null +++ b/mentorship/summerofcode/mentors-guideline.md @@ -0,0 +1,26 @@ +# GSoC Mentor's Guideline + +##### Introduction + +Hey there! Welcome to the Google Summer of Code (GSoC) mentors' guideline. As a mentor, you are crucial in guiding and supporting contributors throughout their GSoC journey. This guideline outlines key responsibilities, best practices, and tips to ensure a successful mentoring experience. + +### Key Responsibilities + +To participate in the Program, mentors must be contributors or maintainers to any project run by AsyncAPI and not be a participant in the Program. Here are some key responsibilities we expect from our mentors. + +- You'll need to provide guidance, support, and direction to your GSoC contributors throughout the project timeline. It's important to encourage collaboration among GSoC contributors and mentors as well. You'll also need to set reasonable expectations and clearly define project goals, milestones, and expectations at the beginning of the Program. + +- Regular communication is also essential. You'll need to communicate effectively with your contributors through preferred channels such as email, Slack, or video calls. Be readily available and responsive to GSoC contributors' questions, concerns, and requests for assistance. Remember to review code submissions, provide constructive feedback, and help contributors improve their coding skills. + +- Please also encourage contributors to engage with the AsyncAPI community, attend meetings, seek help from fellow community members, and encourage them to share their achievements and milestones with the rest of the community. Make sure that project documentation is up-to-date and accessible for reference to interested contributors. +### Contributors Selection Process + +When it comes to selecting contributors for GSoC, there are a few things you should consider as a mentor: + +- You must ensure their proposal aligns well with the project goals, objectives, and requirements. Assess their technical skills and proficiency in relevant programming languages, tools, and technologies required for the project. And don't hesitate to interview candidates if you need to be more convinced by their proposals. + +- You'll need to assess communication skills, responsiveness, and the ability to collaborate effectively with mentors and the community. These are also important points to consider. You should also evaluate the interested GSoC contributor's commitment level, availability, and willingness to dedicate time and effort to the project throughout the Program. Look at past contributions, code submissions, or involvement in open-source projects to scale the GSoC contributor's experience and dedication to the community. + +### Conclusion + +Thank you for your dedication and commitment as a GSoC mentor. Your guidance and support are invaluable in helping contributors succeed and contribute to AsyncAPI. Best of luck for a productive and rewarding GSoC mentoring experience! diff --git a/tweets/recurring-discuss-ideas/2024-02-01.tweet b/tweets/recurring-discuss-ideas/2024-02-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-02-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-discuss-ideas/2024-03-01.tweet b/tweets/recurring-discuss-ideas/2024-03-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-03-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-discuss-ideas/2024-04-01.tweet b/tweets/recurring-discuss-ideas/2024-04-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-04-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-discuss-ideas/2024-05-01.tweet b/tweets/recurring-discuss-ideas/2024-05-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-05-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-discuss-ideas/2024-06-01.tweet b/tweets/recurring-discuss-ideas/2024-06-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-06-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-discuss-ideas/2024-07-01.tweet b/tweets/recurring-discuss-ideas/2024-07-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-07-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-discuss-ideas/2024-08-01.tweet b/tweets/recurring-discuss-ideas/2024-08-01.tweet new file mode 100644 index 000000000..92b19fefe --- /dev/null +++ b/tweets/recurring-discuss-ideas/2024-08-01.tweet @@ -0,0 +1,5 @@ +Do you have some nice ideas for #AsyncAPI-related tools? Do you want to validate and share with the AsyncAPI community? + +Drop it 👇 and let us have an open discussion 🚀 + +https://github.com/asyncapi/community/discussions/categories/ideas \ No newline at end of file diff --git a/tweets/recurring-slack-link/2024-02-03.tweet b/tweets/recurring-slack-link/2024-02-03.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-02-03.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 diff --git a/tweets/recurring-slack-link/2024-02-10.tweet b/tweets/recurring-slack-link/2024-02-10.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-02-10.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 diff --git a/tweets/recurring-slack-link/2024-02-17.tweet b/tweets/recurring-slack-link/2024-02-17.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-02-17.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 diff --git a/tweets/recurring-slack-link/2024-02-24.tweet b/tweets/recurring-slack-link/2024-02-24.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-02-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 diff --git a/tweets/recurring-slack-link/2024-03-02.tweet b/tweets/recurring-slack-link/2024-03-02.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-03-02.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 diff --git a/tweets/recurring-slack-link/2024-03-09.tweet b/tweets/recurring-slack-link/2024-03-09.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-03-09.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 diff --git a/tweets/recurring-slack-link/2024-03-16.tweet b/tweets/recurring-slack-link/2024-03-16.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-03-16.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 diff --git a/tweets/recurring-slack-link/2024-03-23.tweet b/tweets/recurring-slack-link/2024-03-23.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-03-23.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 diff --git a/tweets/recurring-slack-link/2024-03-30.tweet b/tweets/recurring-slack-link/2024-03-30.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-03-30.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 diff --git a/tweets/recurring-slack-link/2024-04-06.tweet b/tweets/recurring-slack-link/2024-04-06.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-04-06.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 diff --git a/tweets/recurring-slack-link/2024-04-13.tweet b/tweets/recurring-slack-link/2024-04-13.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-04-13.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 diff --git a/tweets/recurring-slack-link/2024-04-20.tweet b/tweets/recurring-slack-link/2024-04-20.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-04-20.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 diff --git a/tweets/recurring-slack-link/2024-04-27.tweet b/tweets/recurring-slack-link/2024-04-27.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-04-27.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 diff --git a/tweets/recurring-slack-link/2024-05-04.tweet b/tweets/recurring-slack-link/2024-05-04.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-05-04.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 diff --git a/tweets/recurring-slack-link/2024-05-11.tweet b/tweets/recurring-slack-link/2024-05-11.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-05-11.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 diff --git a/tweets/recurring-slack-link/2024-05-18.tweet b/tweets/recurring-slack-link/2024-05-18.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-05-18.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 diff --git a/tweets/recurring-slack-link/2024-05-25.tweet b/tweets/recurring-slack-link/2024-05-25.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-05-25.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 diff --git a/tweets/recurring-slack-link/2024-06-01.tweet b/tweets/recurring-slack-link/2024-06-01.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-06-01.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 diff --git a/tweets/recurring-slack-link/2024-06-08.tweet b/tweets/recurring-slack-link/2024-06-08.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-06-08.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 diff --git a/tweets/recurring-slack-link/2024-06-15.tweet b/tweets/recurring-slack-link/2024-06-15.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-06-15.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 diff --git a/tweets/recurring-slack-link/2024-06-22.tweet b/tweets/recurring-slack-link/2024-06-22.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-06-22.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 diff --git a/tweets/recurring-slack-link/2024-06-29.tweet b/tweets/recurring-slack-link/2024-06-29.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-06-29.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 diff --git a/tweets/recurring-slack-link/2024-07-06.tweet b/tweets/recurring-slack-link/2024-07-06.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-07-06.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 diff --git a/tweets/recurring-slack-link/2024-07-13.tweet b/tweets/recurring-slack-link/2024-07-13.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-07-13.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 diff --git a/tweets/recurring-slack-link/2024-07-20.tweet b/tweets/recurring-slack-link/2024-07-20.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-07-20.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 diff --git a/tweets/recurring-slack-link/2024-07-27.tweet b/tweets/recurring-slack-link/2024-07-27.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-07-27.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 diff --git a/tweets/recurring-slack-link/2024-08-03.tweet b/tweets/recurring-slack-link/2024-08-03.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-08-03.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 diff --git a/tweets/recurring-slack-link/2024-08-10.tweet b/tweets/recurring-slack-link/2024-08-10.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-08-10.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 diff --git a/tweets/recurring-slack-link/2024-08-17.tweet b/tweets/recurring-slack-link/2024-08-17.tweet new file mode 100644 index 000000000..0bd3e8865 --- /dev/null +++ b/tweets/recurring-slack-link/2024-08-17.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 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 diff --git a/voteTrackingFile.json b/voteTrackingFile.json new file mode 100644 index 000000000..419020d19 --- /dev/null +++ b/voteTrackingFile.json @@ -0,0 +1,587 @@ +[ + { + "name": "Mayaleeeee", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-17", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "aayushmau5", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-05-28", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "imabp", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "akshatnema", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "anshgoyalevil", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "anandsunderraman", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "Shurtu-gal", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-17", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "CameronRushton", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Abstain", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-06-13", + "isVotedInLast3Months": "true", + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 1, + "notParticipatingCount": 2 + }, + { + "name": "dalelane", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Abstain", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-17", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 1, + "notParticipatingCount": 2 + }, + { + "name": "fmvilas", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-05-28", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "jonaslagoni", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-16", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "KhudaDad414", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-05-29", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "lbroudoux", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-16", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "M3lkior", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-04-12", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 3 + }, + { + "name": "derberg", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-16", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "magicmatatjahu", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-06-13", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "AceTheCreator", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-05-29", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "NektariosFifes", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "Member has not participated in all previous voting process.", + "isVotedInLast3Months": "Member has not participated in all previous voting process.", + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 0, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 4 + }, + { + "name": "Pakisan", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-16", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "theschles", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-18", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "princerajpoot20", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-05-28", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "rcoppen", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-17", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 3 + }, + { + "name": "Amzani", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-06-13", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "smoya", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "Souvikns", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-17", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "quetzalliwrites", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-06-04", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "BOLT04", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-06-08", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "dan-r", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-22", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 3 + }, + { + "name": "Tenischev", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-07-16", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 3 + }, + { + "name": "Samridhi-98", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-16", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "ivangsa", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-17", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 2, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 2 + }, + { + "name": "Florence-Njeri", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "whitlockjc", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "Not participated", + "lastParticipatedVoteTime": "2024-06-13", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 3 + }, + { + "name": "VisualBean", + "Donate kotlin-asyncapi$$1313": "Abstain", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-22", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 1, + "notParticipatingCount": 0 + }, + { + "name": "kennethaasan", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-23", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "GreenRover", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "Not participated", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-24", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 1, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 3 + }, + { + "name": "thulieblack", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-20", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 4, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 0 + }, + { + "name": "devilkiller-ag", + "Donate kotlin-asyncapi$$1313": "Not participated", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "In favor", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-05-28", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + }, + { + "name": "sambhavgupta0705", + "Donate kotlin-asyncapi$$1313": "In favor", + "Proposal for Admin Rights for CoC Main Committee on Slack$$1227": "Not participated", + "chore: add Marketing WORKING_GROUP$$1130": "In favor", + "docs: add instruction how voting automation works$$1155": "In favor", + "lastParticipatedVoteTime": "2024-07-24", + "isVotedInLast3Months": true, + "lastVoteClosedTime": "2024-07-26", + "firstVoteClosedTime": "2024-04-12", + "agreeCount": 3, + "disagreeCount": 0, + "abstainCount": 0, + "notParticipatingCount": 1 + } +] \ No newline at end of file diff --git a/voting.md b/voting.md new file mode 100644 index 000000000..47bc821e4 --- /dev/null +++ b/voting.md @@ -0,0 +1,63 @@ +## Overview + +In the [search for the right governance model](https://www.asyncapi.com/blog/governance-motivation), we ended up defining a Technical Steering Committee (TSC) that can help make decisions related to the entire AsyncAPI Initiative and not only a specific repository. TSC voting is described in the official [Charter](https://github.com/asyncapi/community/blob/master/CHARTER.md#4-tsc-voting). + +To make the voting process easier with proper automation, we use [**Git Vote**](https://github.com/cncf/gitvote) bot. + +### Voting Location + +- Voting must only take place in the [community](https://github.com/asyncapi/community) repository. +- Voting automation works only with GitHub Issues and Pull Requests. + +The Discussions should only be used for initial discussion, brainstorming ideas, or seeking initial support. + +In the majority of cases, topics we vote on introduce new rules or ways of doing things. This implies that proper community documentation is needed for these topics. We recommend using Pull Requests instead of Issues to conduct voting on a topic, as it allows you to provide context and finalize documentation. + +### Voting Rules + +* Only votes from [TSC members](https://www.asyncapi.com/community/tsc) are counted. You are still encouraged to participate in voting, even if your vote is not binding. +* TSC members have at least 7 calendar days to vote. As a community, we did not set an exact voting deadline and only have a rule that you can translate into: "Just be nice and give people at least 7 days to get familiar with the topic so they can vote." Our automation is set for 4 weeks to take into account all possible limitations related to holidays and other events. +* TSC members can skip some votes, although, if you do not have an opinion, please participate with 👀 to indicate that you saw a vote but you have no opinion and abstain. There is one strict rule, though: if you do not participate in voting within three months, you will stop being a TSC member. It has nothing to do, though, with your maintainer responsibilities. +* The vote is completed when more than 50% of the voting is in favor. + +### Voting Process + +#### Start Voting + +1. The TSC member adds a `/vote` comment to an Issue or a Pull Request. +2. The Git Vote bot creates a comment with instructions on how the voting should be done. It is based on 👍🏼 , 👎🏼 and 👀 emojis. You can still put comments or suggestions. +3. The AsyncAPI bot adds a `vote` label, making it easier to extract information about voted topics and participation. + +#### Check Status + +1. Anyone can add a `/check-vote` comment to an Issue or a Pull Request. +2. The Git Vote bot creates a comment with an update on how many binding votes were provided. And how much the percentage is required to finish the voting process. + +### Cancel Voting + +1. The TSC member adds `/cancel-vote` comment to an Issue or a Pull Request. +2. The Git Vote bot creates a comment. +3. The AsyncAPI bot removes the `vote` label. + +### Finish Voting + +Voting cannot be concluded with a comment; it ends when more than half of the users with binding votes say yes or when the deadline passes. + +The Git Vote bot adds a comment that voting is completed. + +### Tracking Voting + +We store [the voting history of entire TSC](TSC_VOTING_OVERVIEW.md) since voting automation was introduces. + +* 🔕 indicates that the member did not vote. +* 👍 indicates that the member was in favor. +* 👎 indicates that the member was against. +* 👀 indicates that the member abstained from voting. + +Tracking file is automatically updated by a bot after each vote is completed. It also records whether the member has voted in the last 3 months, helping to identify inactive TSC Members. + +### Note + +* As per the [Charter](./CHARTER.md), a quorum is not needed. However, Git Vote has technical limitations, and a quorum should be reached. That's why we allocate 4 weeks for voting, and it's important to actively encourage participation to ensure that the quorum (where votes cast exceed 50% of eligible voters) is met. +* The abstain votes are included in the total number of votes; they are not removed. +* At present, Git Vote is enabled in the community repo only, and the Git Vote bot handles all voting processes. We will add Git Vote to other projects in the future.