feat: improve walkthrough #33837
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: "Lint PR" | |
on: | |
pull_request: | |
types: | |
- opened | |
- edited | |
- synchronize | |
- closed | |
schedule: | |
- cron: "0 8 * * *" | |
permissions: | |
contents: read | |
actions: read | |
pull-requests: write | |
jobs: | |
pr-title: | |
if: ${{ github.event_name == 'pull_request' && github.event.action != 'closed' }} | |
runs-on: ubuntu-latest | |
steps: | |
# Please look up the latest version from | |
# https://github.com/amannn/action-semantic-pull-request/releases | |
- uses: amannn/[email protected] | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
- uses: actions/github-script@v6 | |
with: | |
script: | | |
const AZDO_TICKET_REGEX = 'https:\/\/(dev\.azure\.com\/msazure|msazure\.visualstudio\.com)\/Microsoft%20Teams%20Extensibility'; | |
const AZDO_TICKET_REGEX_WXP = 'https:\/\/office\.visualstudio\.com\/OC'; | |
const pullRequest = context.payload.pull_request; | |
if(pullRequest.title.startsWith("feat")) { | |
const body = pullRequest.body; | |
const match = body?.match(AZDO_TICKET_REGEX) || body?.match(AZDO_TICKET_REGEX_WXP); | |
if(!match) { | |
core.setFailed("Feat PR should contains AZDO tickets"); | |
} | |
} else if(pullRequest.title.startsWith("fix")) { | |
const body = pullRequest.body; | |
const match = body?.match(AZDO_TICKET_REGEX) || body?.match(AZDO_TICKET_REGEX_WXP); | |
if(!match && !body) { | |
core.setFailed("Fix PR should contains AZDO tickets or descrptions"); | |
} | |
} | |
check-format: | |
if: ${{ github.event_name == 'pull_request' && github.event.action != 'closed' }} | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout branch | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
ref: ${{ github.event.pull_request.head.ref }} | |
repository: ${{github.event.pull_request.head.repo.full_name}} | |
- name: setup project | |
uses: ./.github/actions/setup-project | |
- name: prettier check files in PR on Fork | |
if: ${{ github.event.pull_request.head.repo.full_name != 'OfficeDev/TeamsFx' }} | |
run: | | |
git remote add upstream https://github.com/OfficeDev/TeamsFx.git | |
git fetch upstream ${{ github.event.pull_request.base.ref }} | |
VAR=$(realpath .github/scripts/lint-pr.sh) | |
pnpm -r exec -- bash $VAR upstream/${{ github.event.pull_request.base.ref }} | |
- name: prettier check files in PR on local | |
if: ${{ github.event.pull_request.head.repo.full_name == 'OfficeDev/TeamsFx' }} | |
run: | | |
VAR=$(realpath .github/scripts/lint-pr.sh) | |
pnpm -r exec -- bash $VAR origin/${{ github.event.pull_request.base.ref }} | |
- name: Check if there are changes | |
id: changes | |
run: | | |
git add . | |
VAR=$(git diff --cached --name-only) | |
if [ ! -z "$VAR" ] | |
then | |
echo $VAR | |
echo '======================================= Prompt Information ===============================================' | |
echo 'There may be some unformatted files in your PR, please run these commands on Git Bash terminal: ' | |
echo '1. npm run setup' | |
echo '2. VAR=$(realpath .github/scripts/lint-pr.sh) ' | |
echo '3. pnpm -r exec -- bash $VAR ${your-PR-target-branch}' | |
echo 'please replace the ${your-PR-target-branch} as the target branch of your PR, such as origin/dev or upstream/dev' | |
exit 1 | |
fi | |
- name: Check unused strings | |
working-directory: ./packages/fx-core | |
run: npm run checkUnusedStrings | |
shell: bash | |
env: | |
CI: true | |
check-yaml-lint: | |
if: ${{ github.event_name == 'pull_request' && github.event.action != 'closed' }} | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout branch | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
ref: ${{ github.event.pull_request.head.ref }} | |
repository: ${{github.event.pull_request.head.repo.full_name}} | |
- name: Install Yaml lint and mustache | |
run: | | |
pip install yamllint | |
npm install mustache -g | |
echo "{}" > test.json | |
- name: check origin or remote | |
id: remote | |
run: | | |
if [ ${{ github.event.pull_request.head.repo.full_name == 'OfficeDev/TeamsFx' }} ] | |
then | |
echo "target=origin" >> $GITHUB_OUTPUT | |
else | |
echo "target=remote" >> $GITHUB_OUTPUT | |
fi | |
- name: check yaml lint origin | |
run: | | |
TRAGET=${{steps.remote.outputs.target}}/${{ github.event.pull_request.base.ref }} | |
YMLTPL=$(git diff --diff-filter=MARC $TRAGET...HEAD --name-only -- templates | grep -E '.yml.tpl$'|xargs) | |
echo $YMLTPL | |
if [ ! -z "$YMLTPL" ] | |
then | |
for obj in "$YMLTPL" | |
do | |
mustache test.json $obj | yamllint -d "{extends: relaxed, rules: {line-length: {max: 100}}}" - | |
done | |
fi | |
check-sensitive-content: | |
if: ${{ (github.event_name == 'pull_request' && github.event.action != 'closed') || github.event_name == 'schedule' }} | |
runs-on: ubuntu-latest | |
steps: | |
- shell: bash | |
if: ${{ github.event_name == 'pull_request'}} | |
run: | | |
if [ "${{ github.event_name }}" == "push" ]; then | |
echo "depth=$(($(jq length <<< '${{ toJson(github.event.commits) }}') + 1))" >> $GITHUB_ENV | |
echo "branch=${{ github.ref_name }}" >> $GITHUB_ENV | |
fi | |
if [ "${{ github.event_name }}" == "pull_request" ]; then | |
echo "depth=$((${{ github.event.pull_request.commits }} + 1))" >> $GITHUB_ENV | |
echo "branch=${{ github.event.pull_request.head.ref }}" >> $GITHUB_ENV | |
fi | |
- uses: actions/checkout@v4 | |
if: ${{ github.event_name == 'pull_request'}} | |
with: | |
ref: ${{env.branch}} | |
repository: ${{github.event.pull_request.head.repo.full_name}} | |
fetch-depth: ${{env.depth}} | |
- uses: trufflesecurity/trufflehog@main | |
if: ${{ github.event_name == 'pull_request'}} | |
with: | |
extra_args: --only-verified | |
- if: ${{ github.event_name == 'schedule' }} | |
uses: actions/checkout@v4 | |
- if: ${{ github.event_name == 'schedule' }} | |
uses: trufflesecurity/trufflehog@main | |
with: | |
base: "" | |
head: ${{ github.ref_name }} | |
extra_args: --only-verified | |
create-cherry-pick-issue: | |
if: ${{ github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.base.ref, 'release') && !contains(github.event.pull_request.labels.*.name, 'cherry-pick-hotfix') }} | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
issues: write | |
pull-requests: read | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v3 | |
with: | |
fetch-depth: 0 | |
token: ${{ secrets.GITHUB_TOKEN }} | |
- name: Get latest release branch | |
id: get-latest-release | |
run: | | |
# 找出版本号最大的 release 分支,分为两类: | |
# 1. release/NUM 或 release/NUM.NUM 格式 | |
LATEST_NUM_RELEASE=$(git branch -r | grep -E '^ origin/release/[0-9]+(\.[0-9]+)?$' | sed 's/origin\///' | sort -t'/' -k2 -V | tail -n1) | |
# 2. release/VSNUMPNUM 格式 | |
LATEST_VS_RELEASE=$(git branch -r | grep -E '^ origin/release/VS[0-9]+P[0-9]+$' | sed 's/origin\///' | sort -t'/' -k2 -V | tail -n1) | |
echo "latest_vsc_release=$LATEST_NUM_RELEASE" >> $GITHUB_OUTPUT | |
echo "latest_vs_release=$LATEST_VS_RELEASE" >> $GITHUB_OUTPUT | |
- name: Create Issue | |
uses: actions/github-script@v6 | |
with: | |
github-token: ${{ secrets.GITHUB_TOKEN }} # Use a PAT with the required permissions | |
script: | | |
const currentTarget = context.payload.pull_request.base.ref; | |
const latestVSCRelease = '${{ steps.get-latest-release.outputs.latest_vsc_release }}'.trim(); | |
const latestVSRelease = '${{ steps.get-latest-release.outputs.latest_vs_release }}'.trim(); | |
const prNumber = context.payload.pull_request.number; | |
const prTitle = context.payload.pull_request.title; | |
const prAuthor = context.payload.pull_request.user.login; | |
let targetBranches = ['dev']; | |
if (latestVSCRelease && currentTarget !== latestVSCRelease) { | |
targetBranches.push(latestVSCRelease); | |
} | |
if (latestVSRelease && currentTarget !== latestVSRelease) { | |
targetBranches.push(latestVSRelease); | |
} | |
const branchList = targetBranches.map(branch => `- [ ] cherry-pick #${prNumber} to ${branch}`).join('\n'); | |
const issueBody = ` | |
### Cherry-pick Reminder | |
@${prAuthor} Hello! | |
This is an automatically created reminder. Your PR #${prNumber} (\`${prTitle}\`) is being merged into the \`${currentTarget}\` branch. | |
Please ensure to cherry-pick these changes to the following branches: | |
${branchList} | |
#### Steps to Follow: | |
1. Wait for the current PR to be merged. | |
2. Execute the following commands locally: | |
\`\`\`bash | |
git fetch origin | |
git checkout <target_branch> | |
git cherry-pick <commit_hash> | |
git push origin <target_branch> | |
\`\`\` | |
3. Or create a new PR to merge these changes into the above branches. | |
After completion, please check the items above ✓ | |
> Note: This is an automatically created issue. You can close this issue after completing all the operations. | |
`; | |
try { | |
const issue = await github.rest.issues.create({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
title: `[Cherry-pick] PR #${prNumber} needs to be synchronized to other branches`, | |
body: issueBody, | |
labels: ['cherry-pick-hotfix'], | |
assignees: [prAuthor] // Add PR author as assignee | |
}); | |
console.log(`Created issue #${issue.data.number}`); | |
} catch (error) { | |
console.log('Error creating issue:', error); | |
core.setFailed(error.message); | |
} | |