Skip to content

Commit ae23d01

Browse files
authored
Merge branch 'main' into openapi-update-e3d37e33f5d6f3db5d80d5d602d7772843d043867c57c3e0ed3dd0af80aeec77
2 parents c0e79c5 + db05b43 commit ae23d01

11 files changed

Lines changed: 152 additions & 39 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Check for Spammy Issues
2+
on:
3+
issues:
4+
types: [opened]
5+
jobs:
6+
spammy-title-check:
7+
name: Remove issues with spammy titles
8+
if: github.repository == 'github/docs'
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/github-script@626af12fe9a53dc2972b48385e7fe7dec79145c9
12+
with:
13+
github-token: ${{ secrets.DOCUBOT_FR_PROJECT_BOARD_WORKFLOWS_REPO_ORG_READ_SCOPES }}
14+
script: |
15+
16+
const issue = context.payload.issue
17+
const owner = 'github'
18+
const repo = 'docs'
19+
20+
const titleWordCount = issue.title.trim().split(' ').length
21+
const titleWordCountMin = 2
22+
23+
try {
24+
await github.teams.getMembershipForUserInOrg({
25+
org: 'github',
26+
team_slug: 'employees',
27+
username: context.payload.sender.login,
28+
});
29+
30+
// Do not perform this workflow with GitHub employees. This return
31+
// statement only gets hit if the user is a GitHub employee
32+
return
33+
} catch(err) {
34+
// An error will be thrown if the user is not a GitHub employee
35+
// If a user is not a GitHub employee, we should check to see if title has at least the minimum required number of words in it and if it does, we can exit the workflow
36+
37+
if(titleWordCount > titleWordCountMin) {
38+
return
39+
}
40+
}
41+
42+
//
43+
// Assuming the user is not a GitHub employee and the issue title
44+
// has the minimum number of words required, proceed.
45+
//
46+
47+
// Close the issue and add the invalid label
48+
await github.issues.update({
49+
owner: owner,
50+
repo: repo,
51+
issue_number: issue.number,
52+
labels: ['invalid'],
53+
state: 'closed'
54+
});
55+
56+
// Comment on the issue
57+
await github.issues.createComment({
58+
owner: owner,
59+
repo: repo,
60+
issue_number: issue.number,
61+
body: "This issue appears to have been opened accidentally. I'm going to close it now, but feel free to open a new issue or ask any questions in [discussions](https://github.com/github/docs/discussions)!"
62+
});

content/actions/guides/building-and-testing-java-with-gradle.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ steps:
113113
${{ runner.os }}-gradle-
114114
- name: Build with Gradle
115115
run: ./gradlew build
116+
- name: Cleanup Gradle Cache
117+
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
118+
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
119+
run: |
120+
rm -f ~/.gradle/caches/modules-2/modules-2.lock
121+
rm -f ~/.gradle/caches/modules-2/gc.properties
116122
```
117123
{% endraw %}
118124

content/developers/apps/creating-ci-tests-with-the-checks-api.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ The code above gets the full repository name and the head SHA of the commit from
435435

436436
### Step 2.3. Running RuboCop
437437

438-
Great! You're cloning the repository and creating check runs using your CI server. Now you'll get into the nitty gritty details of the [RuboCop linter](https://rubocop.readthedocs.io/en/latest/basic_usage/#rubocop-as-a-code-style-checker) and [Checks API annotations](/rest/reference/checks#create-a-check-run).
438+
Great! You're cloning the repository and creating check runs using your CI server. Now you'll get into the nitty gritty details of the [RuboCop linter](https://docs.rubocop.org/rubocop/usage/basic_usage.html#code-style-checker) and [Checks API annotations](/rest/reference/checks#create-a-check-run).
439439

440440
The following code runs RuboCop and saves the style code errors in JSON format. Add this code below the call to `clone_repository` you added in the [previous step](#step-22-cloning-the-repository) and above the code that updates the check run to complete.
441441

@@ -447,7 +447,7 @@ logger.debug @report
447447
@output = JSON.parse @report
448448
```
449449

450-
The code above runs RuboCop on all files in the repository's directory. The option `--format json` is a handy way to save a copy of the linting results in a machine-parsable format. See the [RuboCop docs](https://rubocop.readthedocs.io/en/latest/formatters/#json-formatter) for details and an example of the JSON format.
450+
The code above runs RuboCop on all files in the repository's directory. The option `--format json` is a handy way to save a copy of the linting results in a machine-parsable format. See the [RuboCop docs](https://docs.rubocop.org/rubocop/formatters.html#json-formatter) for details and an example of the JSON format.
451451

452452
Because this code stores the RuboCop results in a `@report` variable, it can safely remove the checkout of the repository. This code also parses the JSON so you can easily access the keys and values in your GitHub App using the `@output` variable.
453453

@@ -588,7 +588,7 @@ This code limits the total number of annotations to 50. But you can modify this
588588

589589
When the `offense_count` is zero, the CI test is a `success`. If there are errors, this code sets the conclusion to `neutral` in order to prevent strictly enforcing errors from code linters. But you can change the conclusion to `failure` if you would like to ensure that the check suite fails when there are linting errors.
590590

591-
When errors are reported, the code above iterates through the `files` array in the RuboCop report. For each file, it extracts the file path and sets the annotation level to `notice`. You could go even further and set specific warning levels for each type of [RuboCop Cop](https://rubocop.readthedocs.io/en/latest/cops/), but to keep things simpler in this quickstart, all errors are set to a level of `notice`.
591+
When errors are reported, the code above iterates through the `files` array in the RuboCop report. For each file, it extracts the file path and sets the annotation level to `notice`. You could go even further and set specific warning levels for each type of [RuboCop Cop](https://docs.rubocop.org/rubocop/cops.html), but to keep things simpler in this quickstart, all errors are set to a level of `notice`.
592592

593593
This code also iterates through each error in the `offenses` array and collects the location of the offense and error message. After extracting the information needed, the code creates an annotation for each error and stores it in the `annotations` array. Because annotations only support start and end columns on the same line, `start_column` and `end_column` are only added to the `annotation` object if the start and end line values are the same.
594594

@@ -718,7 +718,7 @@ If the annotations are related to a file already included in the PR, the annotat
718718

719719
If you've made it this far, kudos! 👏 You've already created a CI test. In this section, you'll add one more feature that uses RuboCop to automatically fix the errors it finds. You already added the "Fix this" button in the [previous section](#step-25-updating-the-check-run-with-ci-test-results). Now you'll add the code to handle the `requested_action` check run event triggered when someone clicks the "Fix this" button.
720720

721-
The RuboCop tool [offers](https://rubocop.readthedocs.io/en/latest/basic_usage/#auto-correcting-offenses) the `--auto-correct` command-line option to automatically fix errors it finds. When you use the `--auto-correct` feature, the updates are applied to the local files on the server. You'll need to push the changes to GitHub after RuboCop does its magic.
721+
The RuboCop tool [offers](https://docs.rubocop.org/rubocop/usage/basic_usage.html#auto-correcting-offenses) the `--auto-correct` command-line option to automatically fix errors it finds. When you use the `--auto-correct` feature, the updates are applied to the local files on the server. You'll need to push the changes to GitHub after RuboCop does its magic.
722722

723723
To push to a repository, your app must have write permissions for "Repository contents." You set that permission back in [Step 2.2. Cloning the repository](#step-22-cloning-the-repository) to **Read & write**, so you're all set.
724724

content/github/getting-started-with-github/git-cheatsheet.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ versions:
77
enterprise-server: '*'
88
github-ae: '*'
99
---
10-
Learning all available Git commands at once can be a daunting task. Keep one of our [Git Cheat Sheets](https://services.github.com/on-demand/resources/cheatsheets/) nearby for reference. The Using Git Cheat Sheet is available in several languages. For more information, see the [resources page on the GitHub Services website](https://services.github.com/on-demand/resources/).
10+
Learning all available Git commands at once can be a daunting task. Our cheat sheets provide a quick reference for the commands you'll use most often: see "[Git Cheat Sheets](https://training.github.com/)." The "Using Git" cheat sheet is available in several languages.
1111

1212
In addition, take a look at our [Git and GitHub learning resources](/articles/git-and-github-learning-resources/) page that links to guides, videos and more.

layouts/release-notes.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ <h2 class="border-bottom-0 m-0 p-0">
4747
</h2>
4848

4949
{% if patch.release_candidate %}
50-
<span class="IssueLabel bg-orange text-white ml-3">Release Candidate</span>
50+
<span class="IssueLabel bg-orange text-white ml-3" style="white-space: pre">Release Candidate</span>
5151
{% endif %}
5252

53-
<a href="https://enterprise.github.com/releases/{{ patch.version | replace: '-rc', '' }}/download" class="ml-3 text-small text-bold">
53+
<a href="https://enterprise.github.com/releases/{{ patch.downloadVersion }}/download" class="ml-3 text-small text-bold">
5454
Download
5555
</a>
5656

lib/instrument-middleware.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const path = require('path')
2+
const statsd = require('./statsd')
3+
4+
module.exports = function instrumentMiddleware (relativePath) {
5+
// Requires the file as if it were being required from '../middleware/index.js'.
6+
// This is a little wonky, but let's us write `app.use(instrument(path))` and
7+
// maintain the name of the file, instead of hard-coding it for each middleware.
8+
const middleware = require(path.resolve(__dirname, '../middleware', relativePath))
9+
10+
// Check if the middleware is an async function, to use the appropriate timer
11+
const isAsyncFunction = middleware.constructor.name === 'AsyncFunction'
12+
13+
// Add a tag so we can see all middleware together
14+
const tags = { middleware: path.basename(relativePath) }
15+
16+
return isAsyncFunction
17+
? statsd.asyncTimer(middleware, 'middleware', tags)
18+
: statsd.timer(middleware, 'middleware', tags)
19+
}

middleware/contextualizers/enterprise-release-notes.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ const enterpriseReleases = require('../../lib/enterprise-server-releases').suppo
99
*/
1010
function sortPatchKeys (release, version) {
1111
const keys = Object.keys(release)
12-
.map(key => ({ version: `${version}.${key}`, patchVersion: key, ...release[key] }))
12+
.map(key => {
13+
const keyWithDots = key.replace(/-/g, '.')
14+
return {
15+
version: `${version}.${keyWithDots}`,
16+
patchVersion: keyWithDots,
17+
downloadVersion: `${version}.${keyWithDots.replace(/\.rc\d*$/, '')}`,
18+
...release[key]
19+
}
20+
})
1321
return keys
1422
.sort((a, b) => {
1523
if (semver.gt(a.version, b.version)) return -1

middleware/index.js

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const express = require('express')
2+
const instrument = require('../lib/instrument-middleware')
23

34
const isDevelopment = process.env.NODE_ENV === 'development'
45

@@ -24,7 +25,7 @@ module.exports = function (app) {
2425
// See https://expressjs.com/en/guide/behind-proxies.html
2526
app.set('trust proxy', 1)
2627
app.use(require('./rate-limit'))
27-
app.use(require('./handle-invalid-paths'))
28+
app.use(instrument('./handle-invalid-paths'))
2829

2930
// *** Security ***
3031
app.use(require('./cors'))
@@ -43,50 +44,50 @@ module.exports = function (app) {
4344
// *** Config and context for redirects ***
4445
app.use(require('./req-utils')) // Must come before record-redirect and events
4546
app.use(require('./record-redirect'))
46-
app.use(require('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages
47-
app.use(asyncMiddleware(require('./context'))) // Must come before early-access-*, handle-redirects
47+
app.use(instrument('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages
48+
app.use(asyncMiddleware(instrument('./context'))) // Must come before early-access-*, handle-redirects
4849

4950
// *** Redirects, 3xx responses ***
5051
// I ordered these by use frequency
5152
app.use(require('connect-slashes')(false))
52-
app.use(require('./redirects/external'))
53-
app.use(require('./redirects/help-to-docs'))
54-
app.use(require('./redirects/language-code-redirects')) // Must come before contextualizers
55-
app.use(require('./redirects/handle-redirects')) // Must come before contextualizers
53+
app.use(instrument('./redirects/external'))
54+
app.use(instrument('./redirects/help-to-docs'))
55+
app.use(instrument('./redirects/language-code-redirects')) // Must come before contextualizers
56+
app.use(instrument('./redirects/handle-redirects')) // Must come before contextualizers
5657

5758
// *** Config and context for rendering ***
58-
app.use(require('./find-page')) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page
59-
app.use(require('./block-robots'))
59+
app.use(instrument('./find-page')) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page
60+
app.use(instrument('./block-robots'))
6061

6162
// *** Rendering, 2xx responses ***
6263
// I largely ordered these by use frequency
63-
app.use(require('./archived-enterprise-versions-assets')) // Must come before static/assets
64+
app.use(instrument('./archived-enterprise-versions-assets')) // Must come before static/assets
6465
app.use('/dist', express.static('dist'))
6566
app.use('/assets', express.static('assets'))
6667
app.use('/public', express.static('data/graphql'))
67-
app.use('/events', require('./events'))
68-
app.use('/csrf', require('./csrf-route'))
69-
app.use('/search', require('./search'))
70-
app.use(require('./archived-enterprise-versions'))
71-
app.use(require('./robots'))
72-
app.use(/(\/.*)?\/early-access$/, require('./contextualizers/early-access-links'))
73-
app.use(require('./categories-for-support-team'))
74-
app.use(require('./loaderio-verification'))
75-
app.get('/_500', asyncMiddleware(require('./trigger-error')))
68+
app.use('/events', instrument('./events'))
69+
app.use('/csrf', instrument('./csrf-route'))
70+
app.use('/search', instrument('./search'))
71+
app.use(instrument('./archived-enterprise-versions'))
72+
app.use(instrument('./robots'))
73+
app.use(/(\/.*)?\/early-access$/, instrument('./contextualizers/early-access-links'))
74+
app.use(instrument('./categories-for-support-team'))
75+
app.use(instrument('./loaderio-verification'))
76+
app.get('/_500', asyncMiddleware(instrument('./trigger-error')))
7677

7778
// *** Preparation for render-page ***
78-
app.use(asyncMiddleware(require('./contextualizers/enterprise-release-notes')))
79-
app.use(require('./contextualizers/graphql'))
80-
app.use(require('./contextualizers/rest'))
81-
app.use(require('./contextualizers/webhooks'))
82-
app.use(require('./breadcrumbs'))
83-
app.use(require('./early-access-breadcrumbs'))
84-
app.use(require('./enterprise-server-releases'))
85-
app.use(require('./dev-toc'))
86-
app.use(require('./featured-links'))
87-
app.use(require('./learning-track'))
79+
app.use(asyncMiddleware(instrument('./contextualizers/enterprise-release-notes')))
80+
app.use(instrument('./contextualizers/graphql'))
81+
app.use(instrument('./contextualizers/rest'))
82+
app.use(instrument('./contextualizers/webhooks'))
83+
app.use(instrument('./breadcrumbs'))
84+
app.use(instrument('./early-access-breadcrumbs'))
85+
app.use(instrument('./enterprise-server-releases'))
86+
app.use(instrument('./dev-toc'))
87+
app.use(instrument('./featured-links'))
88+
app.use(instrument('./learning-track'))
8889

8990
// *** Rendering, must go last ***
90-
app.get('/*', asyncMiddleware(require('./render-page')))
91+
app.get('/*', asyncMiddleware(instrument('./render-page')))
9192
app.use(require('./handle-errors'))
9293
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@
161161
"test": "jest && eslint . && prettier -c \"**/*.{yml,yaml}\" && npm run check-deps",
162162
"prebrowser-test": "npm run build",
163163
"browser-test": "start-server-and-test browser-test-server 4001 browser-test-tests",
164-
"browser-test-server": "cross-env NODE_ENV=production ENABLED_LANGUAGES='en,ja' PORT=4001 node server.js",
164+
"browser-test-server": "cross-env NODE_ENV=production PORT=4001 node server.js",
165165
"browser-test-tests": "cross-env BROWSER=1 jest tests/browser/browser.js",
166166
"sync-search": "start-server-and-test sync-search-server 4002 sync-search-indices",
167167
"sync-search-dry-run": "DRY_RUN=1 npm run sync-search",

0 commit comments

Comments
 (0)