feat(tools): Add Crowdin PR creator action (#41383)

Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>
This commit is contained in:
Randell Dawson
2021-03-09 09:57:40 -07:00
committed by GitHub
parent 18068cdeaa
commit 75dc001aea
7 changed files with 317 additions and 165 deletions

View File

@ -84,62 +84,21 @@ jobs:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_CLIENT }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_CLIENT }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }} CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }}
- name: Install Dependencies
working-directory: ./tools
run: |
cd ./crowdin
npm ci
# Generate PR - all languages should go ABOVE this. # # Generate PR - all languages should go ABOVE this. #
- name: Create PR - name: Create PR
uses: actions/github-script@v3 uses: ./tools/crowdin/actions/pr-creator
with: with:
github-token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }} github-token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
script: |
const branchExists = await github.repos.getBranch({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
branch: 'i18n-sync-client' branch: 'i18n-sync-client'
}).catch(err => { owner-repo: 'freeCodeCamp/freeCodeCamp'
console.info("Branch does not exist. Likely no changes in download?"); base: 'main'
}); title: 'chore(i18n,client): processed translations'
if (!branchExists || branchExists.status !== 200) {
return;
}
const pullRequestExists = await github.pulls.list({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
head: 'freeCodeCamp:i18n-sync-client'
});
if (pullRequestExists.data.length) {
console.info("It looks like a pull request already exists for this branch.");
return;
}
const PR = await github.pulls.create({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
head: 'i18n-sync-client',
base: 'main',
title: 'chore(i18n,client): processed translations',
body: 'This PR was opened auto-magically by Crowdin.' body: 'This PR was opened auto-magically by Crowdin.'
}).catch(err => { labels: 'crowdin-sync, scope: i18n, scope: UI'
console.info("Unpredicted error occurred when trying to create the PR."); reviewers: 'RandellDawson, nhcarrigan'
console.error(err);
});
if (!PR || PR.status !== 201) {
return;
}
const PRNumber = PR.data.number;
await github.issues.addLabels({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
issue_number: PRNumber,
labels: [
"crowdin-sync",
"scope: i18n",
"scope: UI"
]
});
await github.pulls.requestReviewers({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
pull_number: PRNumber,
reviewers: [
'RandellDawson',
'nhcarrigan'
]
});

View File

@ -85,62 +85,21 @@ jobs:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_CURRICULUM }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_CURRICULUM }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }} CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }}
- name: Install Dependencies
working-directory: ./tools
run: |
cd ./crowdin
npm ci
# Generate PR - all languages should go ABOVE this. # # Generate PR - all languages should go ABOVE this. #
- name: Create PR - name: Create PR
uses: actions/github-script@v3 uses: ./tools/crowdin/actions/pr-creator
with: with:
github-token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }} github-token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
script: |
const branchExists = await github.repos.getBranch({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
branch: 'i18n-sync-learn' branch: 'i18n-sync-learn'
}).catch(err => { owner-repo: 'freeCodeCamp/freeCodeCamp'
console.info("Branch does not exist. Likely no changes in download?"); base: 'main'
});
if (!branchExists || branchExists.status !== 200) {
return;
}
const pullRequestExists = await github.pulls.list({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
head: 'freeCodeCamp:i18n-sync-learn'
});
if (pullRequestExists.data.length) {
console.info("It looks like a pull request already exists for this branch.");
return;
}
const PR = await github.pulls.create({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
head: 'i18n-sync-learn',
base: 'main',
title: 'chore(i18n,learn): processed translations', title: 'chore(i18n,learn): processed translations',
body: 'This PR was opened auto-magically by Crowdin.' body: 'This PR was opened auto-magically by Crowdin.'
}).catch(err => { labels: 'crowdin-sync, scope: i18n, scope: learn'
console.info("Unpredicted error occurred when trying to create the PR."); reviewers: 'RandellDawson, nhcarrigan'
console.error(err);
});
if (!PR || PR.status !== 201) {
return;
}
const PRNumber = PR.data.number;
await github.issues.addLabels({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
issue_number: PRNumber,
labels: [
"crowdin-sync",
"scope: i18n",
"scope: learn"
]
});
await github.pulls.requestReviewers({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
pull_number: PRNumber,
reviewers: [
'RandellDawson',
'nhcarrigan'
]
});

View File

@ -118,62 +118,21 @@ jobs:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_DOCS }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID_DOCS }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }} CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_CAMPERBOT_SERVICE_TOKEN }}
- name: Install Dependencies
working-directory: ./tools
run: |
cd ./crowdin
npm ci
# Generate PR - all languages should go ABOVE this. # # Generate PR - all languages should go ABOVE this. #
- name: Create PR - name: Create PR
uses: actions/github-script@v3 uses: ./tools/crowdin/actions/pr-creator
with: with:
github-token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }} github-token: ${{ secrets.CROWDIN_CAMPERBOT_PAT }}
script: |
const branchExists = await github.repos.getBranch({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
branch: 'i18n-sync-docs' branch: 'i18n-sync-docs'
}).catch(err => { owner-repo: 'freeCodeCamp/freeCodeCamp'
console.info("Branch does not exist. Likely no changes in download?"); base: 'main'
});
if (!branchExists || branchExists.status !== 200) {
return;
}
const pullRequestExists = await github.pulls.list({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
head: 'freeCodeCamp:i18n-sync-docs'
});
if (pullRequestExists.data.length) {
console.info("It looks like a pull request already exists for this branch.");
return;
}
const PR = await github.pulls.create({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
head: 'i18n-sync-docs',
base: 'main',
title: 'chore(i18n,docs): processed translations', title: 'chore(i18n,docs): processed translations',
body: 'This PR was opened auto-magically by Crowdin.' body: 'This PR was opened auto-magically by Crowdin.'
}).catch(err => { labels: 'crowdin-sync, scope: i18n, scope: docs'
console.info("Unpredicted error occurred when trying to create the PR."); reviewers: 'RandellDawson, nhcarrigan'
console.error(err);
});
if (!PR || PR.status !== 201) {
return;
}
const PRNumber = PR.data.number;
await github.issues.addLabels({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
issue_number: PRNumber,
labels: [
"crowdin-sync",
"scope: i18n",
"scope: docs"
]
});
await github.pulls.requestReviewers({
owner: 'freeCodeCamp',
repo: 'freeCodeCamp',
pull_number: PRNumber,
reviewers: [
'RandellDawson',
'nhcarrigan'
]
});

View File

@ -0,0 +1,31 @@
name: 'Create Crowdin PRs'
description: "Creates a PR by camperbot for Crowdin translation downloads"
runs:
using: 'node12'
main: './index.js'
inputs:
github-token:
description: 'PAT with write access to create PRs'
required: true
branch:
description: 'Branch name to which commits are made'
required: true
owner-repo:
description: 'owner and repo name specified as ownerName/repoName'
required: true
base:
description: 'base branch name'
default: 'main'
required: true
title:
description: 'PR title'
required: true
body:
description: 'PR body text'
required: true
labels:
description: 'PR labels'
required: false
reviewers:
description: 'Requested PR reviewers'
required: false

View File

@ -0,0 +1,90 @@
/* eslint-disable import/no-unresolved */
/* eslint-disable camelcase */
const core = require('@actions/core');
const githubRoot = require('@actions/github');
(async () => {
try {
const token = core.getInput('github-token');
const branch = core.getInput('branch');
const [owner, repo] = core.getInput('owner-repo').split('/');
if (!owner || !repo) {
core.setFailed('Must specify a valid ownerName/repoName');
}
const base = core.getInput('base');
const title = core.getInput('title');
const body = core.getInput('body');
const labelsStr = core.getInput('labels');
const labels = labelsStr.trim().split(/,\s+/);
const reviewersStr = core.getInput('reviewers');
const reviewers = reviewersStr.trim().split(/,\s+/);
const github = githubRoot.getOctokit(token);
const branchExists = await github.repos
.getBranch({
owner,
repo,
branch
})
.catch(() => {
console.info('Branch does not exist. Likely no changes in download?');
});
if (!branchExists || branchExists.status !== 200) {
return;
}
const pullRequestExists = await github.pulls.list({
owner,
repo,
head: `${owner}:${branch}`
});
if (pullRequestExists.data.length) {
console.info(
'It looks like a pull request already exists for this branch.'
);
return;
}
const PR = await github.pulls
.create({
owner,
repo,
head: branch,
base,
title,
body
})
.catch(err => {
console.info(
'Unpredicted error occurred when trying to create the PR.'
);
console.error(err);
});
if (!PR || PR.status !== 201) {
return;
}
const prNumber = PR.data.number;
console.log(
`https://github.com/freeCodeCamp/freeCodeCamp/pull/${prNumber} created`
);
if (labels && labels.length) {
await github.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels
});
console.log(`Labels ${labels} added to PR`);
}
if (reviewers && reviewers.length) {
await github.pulls.requestReviewers({
owner,
repo,
pull_number: prNumber,
reviewers
});
console.log(`Requested Reviewers ${reviewers} added to PR`);
}
} catch (error) {
core.setFailed(error.message);
}
})();

View File

@ -9,6 +9,121 @@
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
}, },
"@actions/github": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-4.0.0.tgz",
"integrity": "sha512-Ej/Y2E+VV6sR9X7pWL5F3VgEWrABaT292DRqRU6R4hnQjPtC/zD3nagxVdXWiRQvYDh8kHXo7IDmG42eJ/dOMA==",
"requires": {
"@actions/http-client": "^1.0.8",
"@octokit/core": "^3.0.0",
"@octokit/plugin-paginate-rest": "^2.2.3",
"@octokit/plugin-rest-endpoint-methods": "^4.0.0"
}
},
"@actions/http-client": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz",
"integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==",
"requires": {
"tunnel": "0.0.6"
}
},
"@octokit/auth-token": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.5.tgz",
"integrity": "sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==",
"requires": {
"@octokit/types": "^6.0.3"
}
},
"@octokit/core": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.2.5.tgz",
"integrity": "sha512-+DCtPykGnvXKWWQI0E1XD+CCeWSBhB6kwItXqfFmNBlIlhczuDPbg+P6BtLnVBaRJDAjv+1mrUJuRsFSjktopg==",
"requires": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.4.12",
"@octokit/types": "^6.0.3",
"before-after-hook": "^2.1.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
"integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
"requires": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/graphql": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.0.tgz",
"integrity": "sha512-CJ6n7izLFXLvPZaWzCQDjU/RP+vHiZmWdOunaCS87v+2jxMsW9FB5ktfIxybRBxZjxuJGRnxk7xJecWTVxFUYQ==",
"requires": {
"@octokit/request": "^5.3.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-5.3.1.tgz",
"integrity": "sha512-TvVk2QuIA0lQZcIMd6xbdGaGDVeNYIOa3l1ZVagAIk5K3t/WMYbcg4BISNDhzdVhm/TgQB26frAgd/GV81aHJA=="
},
"@octokit/plugin-paginate-rest": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.11.0.tgz",
"integrity": "sha512-7L9xQank2G3r1dGqrVPo1z62V5utbykOUzlmNHPz87Pww/JpZQ9KyG5CHtUzgmB4n5iDRKYNK/86A8D98HP0yA==",
"requires": {
"@octokit/types": "^6.11.0"
}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "4.13.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.4.tgz",
"integrity": "sha512-MGxptzVfiP8O+aydC/riheYzS/yJ9P16M29OuvtZep/sF5sKuOCQP8Wf83YCKXRsQF+ZpYfke2snbPPSIMZKzg==",
"requires": {
"@octokit/types": "^6.12.0",
"deprecation": "^2.3.1"
}
},
"@octokit/request": {
"version": "5.4.14",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz",
"integrity": "sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==",
"requires": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.0.0",
"@octokit/types": "^6.7.1",
"deprecation": "^2.0.0",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.1",
"once": "^1.4.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/request-error": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz",
"integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==",
"requires": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/types": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.12.0.tgz",
"integrity": "sha512-KwOf16soD7aDEEi/PgNeJlHzjZPfrmmNy+7WezSdrpnqZ7YImBJcNnX9+5RUHt1MnA4h8oISRHTqaZDGsX9DRQ==",
"requires": {
"@octokit/openapi-types": "^5.3.0"
}
},
"argparse": { "argparse": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -17,6 +132,16 @@
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
}, },
"before-after-hook": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.0.tgz",
"integrity": "sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ=="
},
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
},
"dotenv": { "dotenv": {
"version": "8.2.0", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
@ -51,6 +176,11 @@
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
}, },
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
},
"js-yaml": { "js-yaml": {
"version": "3.14.1", "version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
@ -70,6 +200,14 @@
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
}, },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"picomatch": { "picomatch": {
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
@ -101,6 +239,21 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=" "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI="
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
} }
} }
} }

View File

@ -10,6 +10,7 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/github": "^4.0.0",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"gray-matter": "^4.0.2", "gray-matter": "^4.0.2",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",