Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

repo sync #11609

Merged
merged 15 commits into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile.openapi_decorator
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ COPY --chown=node:node package-lock.json /openapi-check
ADD --chown=node:node script /openapi-check/script
ADD --chown=node:node lib /openapi-check/lib
ADD --chown=node:node content /openapi-check/content
ADD --chown=node:node data /openapi-check/data

RUN npm ci -D

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -808,7 +808,15 @@ on:

{% data reusables.webhooks.workflow_run_desc %}

{% data reusables.github-actions.branch-requirement %}
{% note %}

**Notes:**

* This event will only trigger a workflow run if the workflow file is on the default branch.

* You can't use `workflow_run` to chain together more than three levels of workflows. For example, if you attempt to trigger five workflows (named `B` to `F`) to run sequentially after an initial workflow `A` has run (that is: `A` → `B` → `C` → `D` → `E` → `F`), workflows `E` and `F` will not be run.

{% endnote %}

| Webhook event payload | Activity types | `GITHUB_SHA` | `GITHUB_REF` |
| --------------------- | -------------- | ------------ | -------------|
Expand Down
49 changes: 14 additions & 35 deletions lib/hydro.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,10 @@ import fetch from 'node-fetch'
import statsd from '../lib/statsd.js'
import FailBot from '../lib/failbot.js'

const SCHEMAS = {
page: 'docs.v0.PageEvent',
exit: 'docs.v0.ExitEvent',
link: 'docs.v0.LinkEvent',
search: 'docs.v0.SearchEvent',
searchResult: 'docs.v0.SearchResultEvent',
navigate: 'docs.v0.NavigateEvent',
survey: 'docs.v0.SurveyEvent',
experiment: 'docs.v0.ExperimentEvent',
redirect: 'docs.v0.RedirectEvent',
clipboard: 'docs.v0.ClipboardEvent',
print: 'docs.v0.PrintEvent',
preference: 'docs.v0.PreferenceEvent',
}

export default class Hydro {
constructor({ secret, endpoint } = {}) {
this.secret = secret || process.env.HYDRO_SECRET
this.endpoint = endpoint || process.env.HYDRO_ENDPOINT
this.schemas = SCHEMAS
}

/**
Expand All @@ -47,20 +31,14 @@ export default class Hydro {
* @param {any} value
*/
async publish(schema, value) {
return this.publishMany([{ schema, value }])
}

/**
* Publish multiple events to Hydro
* @param {[{ schema: string, value: any }]} events
*/
async publishMany(events) {
const body = JSON.stringify({
events: events.map(({ schema, value }) => ({
schema,
value: JSON.stringify(value), // We must double-encode the value property
cluster: 'potomac', // We only have ability to publish externally to potomac cluster
})),
events: [
{
schema,
value: JSON.stringify(value), // We must double-encode the value property
cluster: 'potomac', // We only have ability to publish externally to potomac cluster
},
],
})
const token = this.generatePayloadHmac(body)

Expand All @@ -81,23 +59,24 @@ export default class Hydro {
statsd.increment(`hydro.response_code.${res.status}`, 1, statTags)
statsd.increment('hydro.response_code.all', 1, statTags)

// Track hydro exceptions in Sentry, but don't track 503s because we can't do anything about service availability
if (!res.ok && res.status !== 503) {
// Track hydro exceptions in Sentry,
// but don't track 5xx because we can't do anything about service availability
if (!res.ok && res.status < 500) {
const err = new Error(`Hydro request failed: ${res.statusText}`)
err.status = res.status

const failures = await res.text()

FailBot.report(err, {
hydroStatus: res.status,
hydroText: res.statusText,
hydroFailures: failures,
})

// If the Hydro request failed as an "Unprocessable Entity", log it for diagnostics
if (res.status === 422) {
const failures = await res.json()
console.error(
`Hydro schema validation failed:\n - Request: ${body}\n - Failures: ${JSON.stringify(
failures
)}`
`Hydro schema validation failed:\n - Request: ${body}\n - Failures: ${failures}`
)
}

Expand Down
13 changes: 12 additions & 1 deletion lib/redirects/static/redirect-exceptions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,15 @@
- /billing/managing-billing-for-your-github-account/managing-invoices-for-your-enterprise

/enterprise-cloud@latest/organizations/managing-peoples-access-to-your-organization-with-roles/managing-custom-repository-roles-for-an-organization
- /organizations/managing-peoples-access-to-your-organization-with-roles/managing-custom-repository-roles-for-an-organization
- /organizations/managing-peoples-access-to-your-organization-with-roles/managing-custom-repository-roles-for-an-organization

# The initializing-github-ae.md article is referenced in these code files:
# - lib/github/private_instance_bootstrapper/internal_support_contact.rb
# - lib/github/private_instance_bootstrapper/saml_idp_configuration.rb
# - lib/github/private_instance_bootstrapper/policies_configuration.rb
# This redirect ensures that the links don't resolve to the non-GHAE version
# of the docs as this article only exists in the GHAE docs.

/github-ae@latest/admin/configuration/configuring-your-enterprise/initializing-github-ae
- /admin/configuration/configuring-your-enterprise/initializing-github-ae
- /enterprise-server@latest/admin/configuration/configuring-your-enterprise/initializing-github-ae
17 changes: 16 additions & 1 deletion lib/schema-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ const preferenceSchema = {
},
}

export default {
export const eventSchema = {
oneOf: [
pageSchema,
exitSchema,
Expand All @@ -477,3 +477,18 @@ export default {
preferenceSchema,
],
}

export const hydroNames = {
page: 'docs.v0.PageEvent',
exit: 'docs.v0.ExitEvent',
link: 'docs.v0.LinkEvent',
search: 'docs.v0.SearchEvent',
searchResult: 'docs.v0.SearchResultEvent',
navigate: 'docs.v0.NavigateEvent',
survey: 'docs.v0.SurveyEvent',
experiment: 'docs.v0.ExperimentEvent',
redirect: 'docs.v0.RedirectEvent',
clipboard: 'docs.v0.ClipboardEvent',
print: 'docs.v0.PrintEvent',
preference: 'docs.v0.PreferenceEvent',
}
6 changes: 3 additions & 3 deletions middleware/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import express from 'express'
import { omit } from 'lodash-es'
import Ajv from 'ajv'
import addFormats from 'ajv-formats'
import schema from '../lib/schema-event.js'
import { eventSchema, hydroNames } from '../lib/schema-event.js'

const OMIT_FIELDS = ['type']

Expand All @@ -15,14 +15,14 @@ router.post('/', async function postEvents(req, res, next) {
const isDev = process.env.NODE_ENV === 'development'
const fields = omit(req.body, '_csrf')

if (!ajv.validate(schema, fields)) {
if (!ajv.validate(eventSchema, fields)) {
return res.status(400).json(isDev ? ajv.errorsText() : {})
}

if (req.hydro.maySend()) {
// intentionally don't await this async request
// so that the http response afterwards is sent immediately
req.hydro.publish(req.hydro.schemas[fields.type], omit(fields, OMIT_FIELDS)).catch((e) => {
req.hydro.publish(hydroNames[fields.type], omit(fields, OMIT_FIELDS)).catch((e) => {
if (isDev) console.error(e)
})
}
Expand Down
21 changes: 15 additions & 6 deletions middleware/learning-track.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,22 @@ export default async function learningTrack(req, res, next) {

const currentLearningTrack = { trackName, trackProduct }
const guidePath = getPathWithoutLanguage(getPathWithoutVersion(req.pagePath))
let guideIndex = track.guides.findIndex((path) => path === guidePath)

// The raw track.guides will return all guide paths, need to use getLinkData
// so we only get guides available in the current version
const trackGuides = await getLinkData(track.guides, req.context)

const trackGuidePaths = trackGuides.map((guide) => {
return getPathWithoutLanguage(getPathWithoutVersion(guide.href))
})

let guideIndex = trackGuidePaths.findIndex((path) => path === guidePath)

// The learning track path may use Liquid version conditionals, handle the
// case where the requested path is a learning track path but won't match
// because of a Liquid conditional.
if (guideIndex < 0) {
guideIndex = await indexOfLearningTrackGuide(track.guides, guidePath, req.context)
guideIndex = await indexOfLearningTrackGuide(trackGuidePaths, guidePath, req.context)
}

// Also check if the learning track path is now a redirect to the requested
Expand All @@ -48,14 +57,14 @@ export default async function learningTrack(req, res, next) {
for (const redirect of req.context.page.redirect_from) {
if (guideIndex >= 0) break

guideIndex = await indexOfLearningTrackGuide(track.guides, redirect, req.context)
guideIndex = await indexOfLearningTrackGuide(trackGuidePaths, redirect, req.context)
}
}

if (guideIndex < 0) return noTrack()

if (guideIndex > 0) {
const prevGuidePath = track.guides[guideIndex - 1]
const prevGuidePath = trackGuidePaths[guideIndex - 1]
const result = await getLinkData(prevGuidePath, req.context, { title: true, intro: false })
if (!result) return noTrack()

Expand All @@ -64,8 +73,8 @@ export default async function learningTrack(req, res, next) {
currentLearningTrack.prevGuide = { href, title }
}

if (guideIndex < track.guides.length - 1) {
const nextGuidePath = track.guides[guideIndex + 1]
if (guideIndex < trackGuidePaths.length - 1) {
const nextGuidePath = trackGuidePaths[guideIndex + 1]
const result = await getLinkData(nextGuidePath, req.context, { title: true, intro: false })
if (!result) return noTrack()

Expand Down
24 changes: 0 additions & 24 deletions tests/unit/hydro.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,6 @@ describe('hydro', () => {
})
})

describe('#publishMany', () => {
it('publishes multiple events to Hydro', async () => {
await hydro.publishMany([
{ schema: 'event-name', value: { pizza: true } },
{ schema: 'other-name', value: { salad: false } },
])

expect(params).toEqual({
events: [
{
schema: 'event-name',
value: JSON.stringify({ pizza: true }),
cluster: 'potomac',
},
{
schema: 'other-name',
value: JSON.stringify({ salad: false }),
cluster: 'potomac',
},
],
})
})
})

describe('#generatePayloadHmac', () => {
it('returns a SHA256 HMAC string', () => {
const body = JSON.stringify({ pizza: true })
Expand Down