Skip to content

Lint PR

Lint PR #34094

Workflow file for this run

name: "Lint PR"
on:
pull_request:
types:
- opened
- edited
- synchronize
- closed
schedule:
- cron: "0 8 * * *"
workflow_dispatch:
inputs:
target-branch:
description: "The target branch of the PR (newly)"
required: true
default: "origin/dev"
source-branch:
description: "The source branch of the PR"
required: true
default: "origin/dev"
permissions:
contents: write
actions: read
pull-requests: write
id-token: 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 -Eo 'release/[0-9]+\.[0-9]+(\.[0-9]+)?' | sort -t/ -k2 -V | tail -n1)
# 2. release/VSNUMPNUM 格式
LATEST_VS_RELEASE=$(git branch -r | grep -E '^ origin/release/[Vv][Ss][0-9]+[Pp][0-9]+$' | tr '[:upper:]' '[:lower:]' | 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);
}
generate-changelog:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.inputs.target-branch }}
- name: update changelog
id: update-changelog
working-directory: ./
run: |
git fetch origin ${{ github.event.inputs.source-branch }}:${{ github.event.inputs.source-branch }}
head=$(git merge-base ${{ github.event.inputs.target-branch }} ${{ github.event.inputs.source-branch }})
tempfile=$(mktemp)
REPO_URL="https://github.com/OfficeDev/Teams-toolkit"
history_cli_feat=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/cli | grep "feat:" || true)
history_toolkit_feat=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/vscode-extension | grep "feat:" || true)
history_core_feat=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/fx-core | grep "feat:" || true)
echo $history_core_feat
history_sdk_feat=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/sdk | grep "feat:" || true)
history_sdk_react_feat=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/sdk-react | grep "feat:" || true)
history_dotnet_sdk_feat=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/dotnet-sdk | grep "feat:" || true)
cat <<EOF > "$tempfile"
### RELEASE ${{ github.event.inputs.source-branch }}...${{ github.event.inputs.target-branch }}
### Feature Commits
#### Fx-core
$history_core_feat
#### CLI
$history_cli_feat
#### Extension Toolkit
$history_toolkit_feat
#### SDK
$history_sdk_feat
#### SDK React
$history_sdk_react_feat
#### .Net SDK
$history_dotnet_sdk_feat
EOF
history_cli_fix=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/cli | grep "fix:" || true)
history_toolkit_fix=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/vscode-extension | grep "fix:" || true)
history_core_fix=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/fx-core | grep "fix:" || true)
history_sdk_fix=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/sdk | grep "fix:" || true)
history_sdk_react_fix=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/sdk-react | grep "fix:" || true)
history_dotnet_sdk_fix=$(git log --pretty=format:"- [%s]($REPO_URL/commit/%h)" $head...HEAD -- ./packages/dotnet-sdk | grep "fix:" || true)
cat <<EOF >> "$tempfile"
### Fix Commits
#### Fx-core
$history_core_fix
#### CLI
$history_cli_fix
#### Extension Toolkit
$history_toolkit_fix
#### SDK
$history_sdk_fix
#### SDK React
$history_sdk_react_fix
#### .Net SDK
$history_dotnet_sdk_fix
EOF
cat "$tempfile"
cat ./packages/vscode-extension/PRERELEASE.md >> "$tempfile"
mv "$tempfile" ./packages/vscode-extension/PRERELEASE.md
git checkout -b changelog/${{ github.event.inputs.target-branch }}
echo "=== changelog file path ==="
echo "https://github.com/OfficeDev/teams-toolkit/blob/changelog/${{ github.event.inputs.source-branch }}/packages/vscode-extension/PRERELEASE.md"
body="<h2>CHANGELOG ${{ github.event.inputs.source-branch }} ... ${{ github.event.inputs.target-branch }}</h2><h3><a href='https:\/\/github.com\/OfficeDev\/teams-toolkit\/blob\/changelog\/${{ github.event.inputs.target-branch }}\/packages\/vscode-extension\/PRERELEASE.md'>Click Here to Open Changelog File</a></h3>"
subject="[Changelog] ${{ github.event.inputs.source-branch }} ... ${{ github.event.inputs.target-branch }}"
github_user=${{ github.actor }}
echo "github_user=$github_user"
accounts_file="./.github/accounts.json"
email=$(jq -r --arg user "$github_user" '.[$user]' "$accounts_file")
echo "email=$email"
echo "body=$body" >> $GITHUB_OUTPUT
echo "subject=$subject" >> $GITHUB_OUTPUT
[email protected]
echo "sendTo=$sendTo" >> $GITHUB_OUTPUT
echo "send report to $sendTo"
- name: setup user info
working-directory: ./
run: |
user_info=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/users/${{ github.actor }})
git config --global user.email $(echo $user_info | jq -r '.name')
git config --global user.name $(echo $user_info | jq -r '.name')
git add ./packages/vscode-extension/PRERELEASE.md
git commit -m "dosc: update changelog for release"
git push --force origin changelog/${{ github.event.inputs.target-branch }}
- name: Send E-mail
uses: ./.github/actions/send-email-report
env:
TO: "${{ steps.update-changelog.outputs.sendTo }}"
BODY: '"${{ steps.update-changelog.outputs.body }}"'
SUBJECT: ${{ steps.update-changelog.outputs.subject }}
MAIL_CLIENT_ID: ${{ secrets.TEST_CLEAN_CLIENT_ID }}
MAIL_CLIENT_SECRET: ${{ secrets.TEST_CLEAN_CLIENT_SECRET }}
MAIL_TENANT_ID: ${{ secrets.TEST_CLEAN_TENANT_ID }}