Skip to content

Commit

Permalink
Merge branch 'main' into revert-20087-revert-20069-fix-homepage-versi…
Browse files Browse the repository at this point in the history
…ons-dropdown
  • Loading branch information
sarahs authored Jun 23, 2021
2 parents 0e2aaef + eba49ad commit 3b78be7
Show file tree
Hide file tree
Showing 58 changed files with 554 additions and 159 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ module.exports = {
ecmaVersion: 11
},
rules: {
'import/no-extraneous-dependencies': ['error']
'import/no-extraneous-dependencies': ['error'],
'node/global-require': ['error'],
'import/no-dynamic-require': ['error']
},
overrides: [
{
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ COPY tsconfig.json ./tsconfig.json

RUN npx tsc

# We need to copy data in order to do the build
COPY --chown=node:node data ./data

RUN npm run build

# --------------------------------------------------------------------------------
Expand Down Expand Up @@ -85,7 +88,6 @@ ENV AIRGAP true
# Copy only what's needed to run the server
COPY --chown=node:node assets ./assets
COPY --chown=node:node content ./content
COPY --chown=node:node data ./data
COPY --chown=node:node includes ./includes
COPY --chown=node:node layouts ./layouts
COPY --chown=node:node lib ./lib
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ You must accept the terms of service to publish actions in {% data variables.pro

Before you can publish an action, you'll need to create an action in your repository. For more information, see "[Creating actions](/actions/creating-actions)."

When you plan to publish your action to {% data variables.product.prodname_marketplace %}, you'll need ensure that the repository only includes the metadata file, code, and files necessary for the action. Creating a single repository for the action allows you tag, release, and package the code in a single unit. {% data variables.product.prodname_dotcom %} also uses the action's metadata on your {% data variables.product.prodname_marketplace %} page.
When you plan to publish your action to {% data variables.product.prodname_marketplace %}, you'll need ensure that the repository only includes the metadata file, code, and files necessary for the action. Creating a single repository for the action allows you to tag, release, and package the code in a single unit. {% data variables.product.prodname_dotcom %} also uses the action's metadata on your {% data variables.product.prodname_marketplace %} page.

Actions are published to {% data variables.product.prodname_marketplace %} immediately and aren't reviewed by {% data variables.product.prodname_dotcom %} as long as they meet these requirements:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ jobs:
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
# create temporary keychain
security create-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
# apply provisioning profile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ versions:
github-ae: '*'
---

{% data reusables.actions.environments-beta %}
{% data reusables.actions.ae-beta %}

## About required reviews in workflows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ versions:
---

{% data reusables.actions.enterprise-beta %}
{% data reusables.actions.visualization-beta %}
{% data reusables.actions.enterprise-github-hosted-runners %}
{% data reusables.actions.ae-beta %}

Expand Down
1 change: 0 additions & 1 deletion content/actions/reference/encrypted-secrets.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ versions:
---

{% data reusables.actions.enterprise-beta %}
{% data reusables.actions.environments-beta %}
{% data reusables.actions.enterprise-github-hosted-runners %}
{% data reusables.actions.ae-beta %}

Expand Down
1 change: 0 additions & 1 deletion content/actions/reference/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ versions:
github-ae: '*'
---

{% data reusables.actions.environments-beta %}
{% data reusables.actions.ae-beta %}

## About environments
Expand Down
1 change: 0 additions & 1 deletion content/developers/overview/viewing-deployment-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ topics:
- API
---

{% data reusables.actions.environments-beta %}

You can deliver deployments through {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" %}{% data variables.product.prodname_actions %} and environments or with {% endif %}the REST API and third party apps. {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "[email protected]" %}For more information about {% data variables.product.prodname_actions %}, see "[{% data variables.product.prodname_actions %}](/actions)." {% endif %}For more information about deployments with the REST API, see "[Repositories](/rest/reference/repos#deployments)."

Expand Down
8 changes: 4 additions & 4 deletions content/graphql/guides/forming-calls-with-graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ For more information on the difference between enums and strings, see the [offic

There is a _lot_ more you can do when forming GraphQL calls. Here are some places to look next:

* [Pagination](https://graphql.github.io/learn/pagination/)
* [Fragments](https://graphql.github.io/learn/queries/#fragments)
* [Inline fragments](https://graphql.github.io/learn/queries/#inline-fragments)
* [Directives](https://graphql.github.io/learn/queries/#directives)
* [Pagination](https://graphql.org/learn/pagination/)
* [Fragments](https://graphql.org/learn/queries/#fragments)
* [Inline fragments](https://graphql.org/learn/queries/#inline-fragments)
* [Directives](https://graphql.org/learn/queries/#directives)
52 changes: 52 additions & 0 deletions data/features/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## Feature-based versioning

Feature-based versioning allows us to define and control the versions of an arbitrarily named "feature" in one place.

**Note**: Do not delete `data/features/placeholder.yml` because it is used by tests.

## How it works

Add a new YAML file with the feature name you want to use in this directory. For a feature named `meow`, that would be `data/features/meow.yml`.

Add a `versions` block to the YML file with the short names of the versions the feature is available in. For example:

```yaml
versions:
fpt: '*'
ghes: '>3.1'
ghae: '*'
```
The format and allowed values are the same as the [frontmatter versions property](/content#versions).
### Liquid conditionals
Now you can use `{% if meow %} ... {% endif %}` in content files! Note this is the `if` tag, not the new `ifversion` tag.

### Frontmatter

You can also use the feature in frontmatter in content files:

```yaml
versions:
fpt: '*'
ghes: '>3.1'
feature: 'meow'
```

If you want a content file to apply to more than one feature, you can do this:

```yaml
versions:
fpt: '*'
ghes: '>3.1'
feature: ['meow', 'blorp']
```

## Schema enforcement

The schema for validating the feature versioning lives in [`tests/helpers/schemas/feature-versions.js`](tests/helpers/schemas/feature-versions.js) and is exercised by [`tests/content/lint-files.js`](tests/content/lint-files.js).

## Script to remove feature tags

TBD!
4 changes: 4 additions & 0 deletions data/features/placeholder.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Do not delete! Used by tests.
versions:
ghes: '>3.0'
ghae: '*'
9 changes: 0 additions & 9 deletions data/reusables/actions/environments-beta.md

This file was deleted.

7 changes: 0 additions & 7 deletions data/reusables/actions/visualization-beta.md

This file was deleted.

2 changes: 1 addition & 1 deletion data/reusables/command_line/providing-token-as-password.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ For example, on the command line you would enter the following:

```shell
$ git clone https://{% data variables.command_line.codeblock %}/<em>username</em>/<em>repo</em>.git
Username: <code>your_username</code>
Username: <em>your_username</em>
Password: <em>your_token</em>
```
11 changes: 8 additions & 3 deletions lib/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
const express = require('express')
const middleware = require('../middleware')

const app = express()
require('../middleware')(app)
module.exports = app
function createApp () {
const app = express()
middleware(app)
return app
}

module.exports = createApp
3 changes: 2 additions & 1 deletion lib/feature-flags.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const featureFlags = require('../feature-flags')
const readJsonFile = require('./read-json-file')
const featureFlags = readJsonFile('./feature-flags.json')

// add feature flags as environment variables
Object.entries(featureFlags).forEach(([feature, value]) => {
Expand Down
28 changes: 24 additions & 4 deletions lib/frontmatter.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const fs = require('fs')
const path = require('path')
const parse = require('./read-frontmatter')
const semver = require('semver')
const layouts = require('./layouts')
Expand All @@ -9,8 +11,10 @@ const semverRange = {
conform: semverValidRange,
message: 'Must be a valid SemVer range'
}
const versionIds = Object.keys(require('./all-versions'))
const versionObjs = Object.values(require('./all-versions'))
const guideTypes = ['overview', 'quick_start', 'tutorial', 'how_to', 'reference']
const featureVersions = fs.readdirSync(path.posix.join(process.cwd(), 'data/features'))
.map(file => path.basename(file, '.yml'))

const schema = {
properties: {
Expand Down Expand Up @@ -197,15 +201,31 @@ const schema = {
}
}

const featureVersionsProp = {
feature: {
type: ['string', 'array'],
enum: featureVersions,
items: {
type: 'string'
},
message: 'must be the name (or names) of a feature that matches "filename" in data/features/_filename_.yml'
}
}

schema.properties.versions = {
type: ['object', 'string'], // allow a '*' string to indicate all versions
required: true,
properties: versionIds.reduce((acc, versionId) => {
acc[versionId] = semverRange
properties: versionObjs.reduce((acc, versionObj) => {
acc[versionObj.plan] = semverRange
acc[versionObj.shortName] = semverRange
return acc
}, {})
}, featureVersionsProp)
}

// Support 'github-ae': next
schema.properties.versions.properties['github-ae'] = 'next'
schema.properties.versions.properties.ghae = 'next'

function frontmatter (markdown, opts = {}) {
const defaults = {
schema,
Expand Down
73 changes: 63 additions & 10 deletions lib/get-applicable-versions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
const path = require('path')
const { reduce, sortBy } = require('lodash')
const allVersions = require('./all-versions')
const versionSatisfiesRange = require('./version-satisfies-range')
const checkIfNextVersionOnly = require('./check-if-next-version-only')
const dataDirectory = require('./data-directory')
const encodeBracketedParentheses = require('./encode-bracketed-parentheses')
const featuresDir = path.posix.join(__dirname, '../data/features')

const featureData = dataDirectory(featuresDir, {
preprocess: dataString =>
encodeBracketedParentheses(dataString.trimEnd()),
ignorePatterns: [/README\.md$/]
})

// return an array of versions that an article's product versions encompasses
function getApplicableVersions (frontmatterVersions, filepath) {
Expand All @@ -13,17 +24,63 @@ function getApplicableVersions (frontmatterVersions, filepath) {
return Object.keys(allVersions)
}

// get an array like: [ 'free-pro-team@latest', '[email protected]', 'enterprise-cloud@latest' ]
const applicableVersions = []
// Check for frontmatter that includes a feature name, like:
// fpt: '*'
// feature: 'foo'
// or multiple feature names, like:
// fpt: '*'
// feature: ['foo', 'bar']
// and add the versions affiliated with the feature (e.g., foo) to the frontmatter versions object:
// fpt: '*'
// ghes: '>=2.23'
// ghae: '*'
// where the feature is bringing the ghes and ghae versions into the mix.
const featureVersions = reduce(frontmatterVersions, (result, value, key) => {
if (key === 'feature') {
if (typeof value === 'string') {
Object.assign(result, { ...featureData[value].versions })
} else if (Array.isArray(value)) {
value.forEach(str => {
Object.assign(result, { ...featureData[str].versions })
})
}
delete result[key]
}
return result
}, {})

// We will be evaluating feature versions separately, so we can remove this.
delete frontmatterVersions.feature

// Get available versions for frontmatter and for feature versions.
const foundFeatureVersions = evaluateVersions(featureVersions)
const foundFrontmatterVersions = evaluateVersions(frontmatterVersions)

// Combine them!
const applicableVersions = [...new Set(foundFrontmatterVersions.versions.concat(foundFeatureVersions.versions))]

if (!applicableVersions.length && !foundFrontmatterVersions.isNextVersionOnly && !foundFeatureVersions.isNextVersionOnly) {
throw new Error(`No applicable versions found for ${filepath}. Please double-check the page's \`versions\` frontmatter.`)
}

// Sort them by the order in lib/all-versions.
const sortedVersions = sortBy(applicableVersions, (v) => { return Object.keys(allVersions).indexOf(v) })

return sortedVersions
}

function evaluateVersions (versionsObj) {
let isNextVersionOnly = false

// where frontmatter is something like:
// get an array like: [ 'free-pro-team@latest', '[email protected]', 'enterprise-cloud@latest' ]
const versions = []

// where versions obj is something like:
// fpt: '*'
// ghes: '>=2.19'
// ghae: '*'
// ^ where each key corresponds to a plan's short name (defined in lib/all-versions.js)
Object.entries(frontmatterVersions)
Object.entries(versionsObj)
.forEach(([plan, planValue]) => {
// Special handling for frontmatter that evalues to the next GHES release number or a hardcoded `next`.
isNextVersionOnly = checkIfNextVersionOnly(planValue)
Expand All @@ -37,16 +94,12 @@ function getApplicableVersions (frontmatterVersions, filepath) {
const versionToCompare = relevantVersion.hasNumberedReleases ? relevantVersion.currentRelease : '1.0'

if (versionSatisfiesRange(versionToCompare, planValue)) {
applicableVersions.push(relevantVersion.version)
versions.push(relevantVersion.version)
}
})
})

if (!applicableVersions.length && !isNextVersionOnly) {
throw new Error(`No applicable versions found for ${filepath}. Please double-check the page's \`versions\` frontmatter.`)
}

return applicableVersions
return { versions, isNextVersionOnly }
}

module.exports = getApplicableVersions
3 changes: 1 addition & 2 deletions lib/instrument-middleware.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
const path = require('path')
const statsd = require('./statsd')

module.exports = function instrumentMiddleware (relativePath) {
module.exports = function instrumentMiddleware (middleware, relativePath) {
// Requires the file as if it were being required from '../middleware/index.js'.
// This is a little wonky, but let's us write `app.use(instrument(path))` and
// maintain the name of the file, instead of hard-coding it for each middleware.
const middleware = require(path.resolve(__dirname, '../middleware', relativePath))

// Check if the middleware is an async function, to use the appropriate timer
const isAsyncFunction = middleware.constructor.name === 'AsyncFunction'
Expand Down
14 changes: 14 additions & 0 deletions lib/read-json-file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const fs = require('fs')
const path = require('path')

module.exports = function readJsonFile (xpath) {
return JSON.parse(
fs.readFileSync(
path.join(
process.cwd(),
xpath
),
'utf8'
)
)
}
Loading

0 comments on commit 3b78be7

Please sign in to comment.