Skip to content

chore: add info about who is elected to board 2025 #3

chore: add info about who is elected to board 2025

chore: add info about who is elected to board 2025 #3

name: Ambassador Management Workflow
on:
pull_request_target:
types: [closed]
paths:
- 'AMBASSADORS_MEMBERS.yaml'
jobs:
detect_ambassador_changes:
if: github.event.pull_request.merged
name: Update Ambassadors Members
runs-on: ubuntu-latest
steps:
- name: Checkout base commit
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.base.sha }}
path: community-main
- name: Checkout head commit
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: community
- name: Install js-yaml
run: npm install js-yaml@4.1.0
- name: Compare files
id: compare-files
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const yaml = require('js-yaml');
const currentAmbassadors = yaml.load(fs.readFileSync('./community-main/AMBASSADORS_MEMBERS.yaml', 'utf8'));
const prAmbassadors = yaml.load(fs.readFileSync('./community/AMBASSADORS_MEMBERS.yaml', 'utf8'));
const added = prAmbassadors.filter(
(newObj) => !currentAmbassadors.some((oldObj) => oldObj.github === newObj.github)
);
const removed = currentAmbassadors.filter(
(oldObj) => !prAmbassadors.some((newObj) => newObj.github === oldObj.github)
);
if (added.length > 0) {
core.setOutput("newAmbassadors", added.map((obj) => obj.github).join(","));
} else {
core.setOutput("newAmbassadors", "");
}
if (removed.length > 0) {
core.setOutput("removedAmbassadors", removed.map((obj) => obj.github).join(","));
} else {
core.setOutput("removedAmbassadors", "");
}
// Log information for debugging
core.info('Ambassadors in main branch:\n' + yaml.dump(currentAmbassadors));
core.info('Location of Ambassadors in main branch:');
core.info(fs.realpathSync('./community-main/AMBASSADORS_MEMBERS.yaml'));
core.info('Ambassadors in PR branch:\n' + yaml.dump(prAmbassadors));
core.info('Location of Ambassadors in PR branch:');
core.info(fs.realpathSync('./community/AMBASSADORS_MEMBERS.yaml'));
- name: Debug newAmbassadors output
run: |
echo "newAmbassadors = ${{ steps.compare-files.outputs.newAmbassadors }}"
- name: Debug removedAmbassadors output
run: |
echo "removedAmbassadors = ${{ steps.compare-files.outputs.removedAmbassadors }}"
outputs:
newAmbassadors: ${{ steps.compare-files.outputs.newAmbassadors }}
removedAmbassadors: ${{ steps.compare-files.outputs.removedAmbassadors }}
add_ambassador:
needs: detect_ambassador_changes
if: needs.detect_ambassador_changes.outputs.newAmbassadors != ''
runs-on: ubuntu-latest
steps:
- name: Invite new ambassadors to the organization
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN_ORG_ADMIN }}
script: |
const newAmbassadors = '${{ needs.detect_ambassador_changes.outputs.newAmbassadors }}'.split(',');
for (const ambassador of newAmbassadors) {
try {
await github.request('PUT /orgs/{org}/memberships/{username}', {
org: 'asyncapi',
username: ambassador
});
} catch (error) {
core.setFailed(`Failed to add ${ambassador} to the organization: ${error.message}`);
}
}
- name: Add new ambassadors to the team
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN_ORG_ADMIN }}
script: |
const newAmbassadors = '${{ needs.detect_ambassador_changes.outputs.newAmbassadors }}'.split(',');
for (const ambassador of newAmbassadors) {
try {
await github.request('PUT /orgs/{org}/teams/{team_slug}/memberships/{username}', {
org: 'asyncapi',
team_slug: 'ambassadors',
username: ambassador
});
} catch (error) {
core.setFailed(`Failed to add ${ambassador} to the team: ${error.message}`);
}
}
outputs:
newAmbassadors: ${{needs.detect_ambassador_changes.outputs.newAmbassadors }}
display_message:
needs: add_ambassador
if: needs.add_ambassador.outputs.newAmbassadors != ''
runs-on: ubuntu-latest
steps:
- name: Display welcome message for new ambassadors
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN }}
script: |
const newAmbassadors = "${{ needs.add_ambassador.outputs.newAmbassadors }}".split(",");
console.log(`New ambassadors: ${newAmbassadors}`);
const welcomeMessage = newAmbassadors.map((ambassador) => `@${ambassador.trim().replace(/^@/, '')} We invited you to join the AsyncAPI organization, and you are added to the team that lists all Ambassadors.\n
Welcome aboard! We are excited to have you as part of the team.`).join("\n");
const { owner, repo } = context.repo;
const { number: issue_number } = context.issue;
await github.rest.issues.createComment({ owner, repo, issue_number, body: welcomeMessage });
remove_ambassador:
needs: detect_ambassador_changes
if: needs.detect_ambassador_changes.outputs.removedAmbassadors != ''
runs-on: ubuntu-latest
steps:
- name: Remove ambassadors from the organization
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN_ORG_ADMIN }}
script: |
const removedAmbassadors = '${{ needs.detect_ambassador_changes.outputs.removedAmbassadors }}'.split(',');
for (const ambassador of removedAmbassadors) {
try {
await github.request('DELETE /orgs/{org}/memberships/{username}', {
org: 'asyncapi',
username: ambassador
});
core.info(`Successfully removed ${ambassador} from the organization.`);
} catch (error) {
if (error.message.startsWith('Cannot find')) {
core.info(`Failed to remove ${ambassador} from the organization: ${error.message}`);
} else {
core.setFailed(`Failed to remove ${ambassador} from the organization: ${error.message}`);
}
}
}
outputs:
removedAmbassadors: ${{ needs.detect_ambassador_changes.outputs.removedAmbassadors }}
remove_ambassador_goodbye:
needs: remove_ambassador
if: needs.remove_ambassador.outputs.removedAmbassadors != ''
runs-on: ubuntu-latest
steps:
- name: Display goodbye message to removed ambassadors
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN_ORG_ADMIN }}
script: |
const removedAmbassadors = "${{ needs.remove_ambassador.outputs.removedAmbassadors }}".split(",");
// Goodbye message to removed ambassadors
const combinedMessages = removedAmbassadors.map((ambassador) => {
return `@${ambassador.trim().replace(/^@/, '')} We would like to express our gratitude for your work as an Ambassador of AsyncAPI Initiative. Your efforts have been immensely valuable to us, and we truly appreciate your dedication. Thank you once again, and we wish you all the best in your future endeavors!\n\n`;
});
const { owner, repo } = context.repo;
const { number: issue_number } = context.issue;
for (const message of combinedMessages) {
await github.rest.issues.createComment({ owner, repo, issue_number, body: message });
}
update_emeritus:
needs: remove_ambassador
if: needs.remove_ambassador.outputs.removedAmbassadors != ''
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Install js-yaml
run: npm install js-yaml@4.1.0
- name: Add Former Ambassador to Emeritus.yaml and print
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const yaml = require('js-yaml');
const path = './Emeritus.yaml';
const yamlContent = [];
// Read the current content of the file
const content = fs.readFileSync(path, 'utf8').trim(); // remove any trailing whitespaces
// Parse the removedAmbassadors comma-separated string to an array
const removedAmbassadors = '${{ needs.remove_ambassador.outputs.removedAmbassadors }}'
.split(',')
.map((ambassador) => ambassador.trim())
.filter(Boolean);
// Strip the first line that contains a comment
yamlContent[0] = content
.split('\n')
.filter((line) => line && line.startsWith('#'));
// Get the actual YAML data
yamlContent[1] = yaml.load(content);
// Extract existing names of Emeritus Ambassadors from the file
const existingEmeritusAmbassadors = new Set(yamlContent[1].emeritus_ambassadors);
// Filter ambassadors who should be added and are not already in the list
const emeritusAmbassadorsDiffList = removedAmbassadors.filter(
(ambassador) => !existingEmeritusAmbassadors.has(ambassador),
);
// Append new ambassadors if there are any new ones
if (emeritusAmbassadorsDiffList.length > 0) {
yamlContent[1].emeritus_ambassadors.push(...emeritusAmbassadorsDiffList);
// Merge the comment and the programmatically changed YAML into new content
// that will be written to `Emeritus.yaml`
const newContent = `${yamlContent[0].join('\n')}\n\n${yaml.dump(yamlContent[1])}`;
// Write the new content back into the YAML file
fs.writeFileSync(path, newContent);
console.log('Updated Emeritus.yaml:\n', fs.readFileSync(path, 'utf8'));
} else {
console.log('No new names to add. Emeritus Ambassador is already in the list.');
}
- name: Config git
run: |
git config --global user.name asyncapi-bot
git config --global user.email info@asyncapi.io
- name: Create new branch
run: |
git checkout -b update-emeritus-${{ github.run_id }}
- name: Commit and push
run: |
git add Emeritus.yaml
if ! git diff --cached --quiet; then
git commit -m "Update Emeritus.yaml"
git remote set-url origin https://x-access-token:${{ secrets.GH_TOKEN }}@github.com/asyncapi/community.git
git push origin update-emeritus-${{ github.run_id }}
else
echo "No updates to Emeritus.yaml; skipping commit/push."
fi
- name: Create PR
run: |
gh pr create --title "docs(community): update latest emeritus list" --body "Updated Emeritus list is available and this PR introduces changes with latest information about Emeritus" --head update-emeritus-${{ github.run_id }}
notify_slack_on_failure:
if: always() && (needs.detect_ambassador_changes.result == 'failure' || needs.add_ambassador.result == 'failure' || needs.display_message.result == 'failure' || needs.update_emeritus.result == 'failure' || needs.remove_ambassador.result == 'failure' || needs.remove_ambassador_goodbye.result == 'failure')
needs: [detect_ambassador_changes, add_ambassador, display_message, update_emeritus, remove_ambassador_goodbye, remove_ambassador]
runs-on: ubuntu-latest
steps:
- name: Report workflow run status to Slack
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{secrets.SLACK_CI_FAIL_NOTIFY}}
SLACK_TITLE: '🚨 Ambassador Management Workflow failed 🚨'
SLACK_MESSAGE: 'Failed to post a message to new Ambassador'
MSG_MINIMAL: true