Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,51 @@ An action's listing page includes the action's version and the workflow syntax r

### Adding an action from the same repository

If an action is defined in the same repository where your workflow file uses the action, you can reference the action with either the ‌`{owner}/{repo}@{ref}` or `./path/to/dir` syntax in your workflow file.
If an action is defined in the same repository where your workflow file uses the action, you can reference the action with the `$/path/to/dir` self repository reference, or with the `{owner}/{repo}@{ref}` or `./path/to/dir` syntax in your workflow file. The `$/` syntax is not available in {% data variables.product.prodname_ghe_server %}.

Example repository file structure:

```shell
|-- hello-world (repository)
| |__ .github
| └── workflows
| └── my-first-workflow.yml
| └── actions
| |__ hello-world-action
| └── action.yml
```

We recommend referencing the action with the `$/path/to/dir` self repository reference. This resolves to the same repository at the running commit, so you do not need to check out the repository first. For more information about how `$/` compares to `{owner}/{repo}@{ref}` and `./`, see [AUTOTITLE](/actions/reference/workflows-and-actions/workflow-syntax#example-using-an-action-in-the-same-repository-as-the-workflow-at-the-running-commit-recommended).

Example workflow file using `$/`:

```yaml
jobs:
my_first_job:
runs-on: ubuntu-latest
steps:
# This step references an action in the same repository at the
# running commit. No repository checkout is required.
- name: Use hello-world-action
uses: $/.github/actions/hello-world-action
```

You can also reference the action with the relative `./path/to/dir` syntax, but it is more error-prone. The path is relative (`./`) to the default working directory (`github.workspace`, `$GITHUB_WORKSPACE`), so it requires a checkout step, and if the action checks out the repository to a location different than the workflow, the relative path must be updated.

{% data reusables.actions.workflows.section-referencing-an-action-from-the-same-repository %}
Example workflow file using `./`:

```yaml
jobs:
my_first_job:
runs-on: ubuntu-latest
steps:
# This step checks out a copy of your repository.
- name: My first step - check out repository
uses: {% data reusables.actions.action-checkout %}
# This step references the directory that contains the action.
- name: Use local hello-world-action
uses: ./.github/actions/hello-world-action
```

The `action.yml` file is used to provide metadata for the action. Learn about the content of this file in [AUTOTITLE](/actions/reference/workflows-and-actions/metadata-syntax).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ runs:
- uses: actions/checkout@main
# References a subdirectory in a public GitHub repository at a specific branch, ref, or SHA
- uses: actions/aws/ec2@main
# References an action in the same repository at the running commit
- uses: $/.github/actions/my-action
# References a local action
- uses: ./.github/actions/my-action
# References a docker public registry action
Expand All @@ -347,6 +349,10 @@ runs:
- uses: docker://alpine:3.8
```

To reference an action stored in the same repository as your composite action, use the `$/` self repository reference, as shown in the `$/.github/actions/my-action` example above. It resolves to that repository at the running commit, so you do not need to check out the repository first, and it must not include an `@{ref}` suffix. The `$/` syntax is not available in {% data variables.product.prodname_ghe_server %}.

For a comparison of `$/`, `{owner}/{repo}@{ref}`, and `./`, see [AUTOTITLE](/actions/reference/workflows-and-actions/workflow-syntax#example-using-an-action-in-the-same-repository-as-the-workflow-at-the-running-commit-recommended).

#### `runs.steps[*].with`

**Optional** A `map` of the input parameters defined by the action. Each input parameter is a key/value pair. For more information, see [Example: Specifying inputs](#example-specifying-inputs).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,11 +597,42 @@ jobs:
uses: actions/aws/ec2@main
```

### Example: Using an action in the same repository as the workflow at the running commit (recommended)

`$/path/to/action`

The `$/` prefix is the self repository reference. It references an action stored in the same repository as the workflow or action that is currently running, and resolves to that repository at the running commit (the same SHA as the running workflow or action). You do not need to check out the repository first, so it is the recommended way to reference an action within its own repository.

The `$/` syntax is not available in {% data variables.product.prodname_ghe_server %}.

A `$/` reference must not include an `@{ref}` suffix. The ref is always the commit the running workflow or action is using, so a reference such as `$/actions/my-action@v1` is invalid.

`$/` always resolves against the repository of the file it appears in, not the repository that called it. For example, if a reusable workflow in one repository is called by a workflow in another repository, a `$/` reference in the called workflow resolves to the called workflow's repository, not the calling workflow's repository. This makes `$/` reliable for action composition, where a relative `./` path would instead resolve against whatever is checked out in the caller's workspace. For using `$/` in a composite action's steps, see [AUTOTITLE](/actions/reference/workflows-and-actions/metadata-syntax#runsstepsuses).

The following table compares the ways to reference an action.

| Syntax | Resolves to | Recommended for |
| ------ | ----------- | --------------- |
| `$/path/to/action` | The same repository as the running workflow or action, at the running commit | Actions in the same repository |
| `{owner}/{repo}@{ref}` | The specified repository at the specified ref | Actions in another repository |
| `./path/to/action` | A path in the runner's checked-out workspace, relative to the default working directory (`{% raw %}${{ github.workspace }}{% endraw %}`) | Edge cases only |

```yaml
on: [push]

jobs:
my_first_job:
runs-on: ubuntu-latest
steps:
# References an action in the same repository at the running commit
- uses: $/.github/actions/hello-world-action
```

### Example: Using an action in the same repository as the workflow

`./path/to/dir`

The path to the directory that contains the action in your workflow's repository. You must check out your repository before using the action.
The path to the directory that contains the action in your workflow's repository. You must check out your repository before using the action, and the `./` path resolves against the runner's workspace rather than the repository of the running workflow. For most cases, use the `$/` syntax shown above instead.

{% data reusables.actions.workflows.section-referencing-an-action-from-the-same-repository %}

Expand Down
2 changes: 1 addition & 1 deletion data/reusables/actions/allow-specific-actions-intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

### Allowing select actions{% ifversion actions-workflow-policy %} and reusable workflows{% endif %} to run

When you choose {% data reusables.actions.policy-label-for-select-actions-workflows %}, local actions{% ifversion actions-workflow-policy %} and reusable workflows{% endif %} are allowed, and there are additional options for allowing other specific actions{% ifversion actions-workflow-policy %} and reusable workflows{% endif %}:
When you choose {% data reusables.actions.policy-label-for-select-actions-workflows %}, local actions (`./` and `$/`){% ifversion actions-workflow-policy %} and reusable workflows{% endif %} are allowed, and there are additional options for allowing other specific actions{% ifversion actions-workflow-policy %} and reusable workflows{% endif %}:

{% data reusables.repositories.settings-permissions-org-policy-note %}

Expand Down
5 changes: 3 additions & 2 deletions data/reusables/actions/reusable-workflow-calling-syntax.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
* `$/.github/workflows/{filename}` for a reusable workflow in the same repository. This is the recommended syntax for referencing a reusable workflow in the same repository. This syntax is not available in {% data variables.product.prodname_ghe_server %}.
* `{owner}/{repo}/.github/workflows/{filename}@{ref}` for reusable workflows in {% ifversion fpt %}public and private{% elsif ghec or ghes %}public, internal and private{% endif %} repositories.
* `./.github/workflows/{filename}` for reusable workflows in the same repository.

In the first option, `{ref}` can be a SHA, a release tag, or a branch name. If a release tag and a branch have the same name, the release tag takes precedence over the branch name. Using the commit SHA is the safest option for stability and security. For more information, see [AUTOTITLE](/actions/reference/security/secure-use#reusing-third-party-workflows).
When you reference a reusable workflow with `{owner}/{repo}` and `@{ref}`, the `{ref}` can be a SHA, a release tag, or a branch name. If a release tag and a branch have the same name, the release tag takes precedence over the branch name. Using the commit SHA is the safest option for stability and security. For more information, see [AUTOTITLE](/actions/reference/security/secure-use#reusing-third-party-workflows).

If you use the second syntax option (without `{owner}/{repo}` and `@{ref}`) the called workflow is from the same commit as the caller workflow. Ref prefixes such as `refs/heads` and `refs/tags` are not allowed. You cannot use contexts or expressions in this keyword.
When you reference a reusable workflow in the same repository using `$/` or `./` (without `{owner}/{repo}` and `@{ref}`), the called workflow is from the same commit as the caller workflow. A `$/` reference must not include an `@{ref}` suffix, and `$/` is not available in {% data variables.product.prodname_ghe_server %}. Ref prefixes such as `refs/heads` and `refs/tags` are not allowed. You cannot use contexts or expressions in this keyword.
3 changes: 3 additions & 0 deletions data/reusables/actions/uses-keyword-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ jobs:
uses: octo-org/this-repo/.github/workflows/workflow-1.yml@172239021f7ba04fe7327647b213799853a9eb89
call-workflow-2-in-local-repo:
uses: ./.github/workflows/workflow-2.yml
# The `$/` syntax is not available in GitHub Enterprise Server.
call-workflow-in-same-repo-at-running-commit:
uses: $/.github/workflows/workflow-2.yml
call-workflow-in-another-repo:
uses: octo-org/another-repo/.github/workflows/workflow.yml@v1
```
52 changes: 52 additions & 0 deletions src/fixtures/tests/playwright-rendering.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,58 @@ test('use sidebar to go to Hello World page', async ({ page }) => {
await expect(page).toHaveTitle(/Hello World - GitHub Docs/)
})

test('sidebar highlights the clicked item optimistically while navigation is pending', async ({
page,
}) => {
// Article pages are getServerSideProps routes, so router.asPath (and thus the real
// aria-current) only updates after the destination loads. The sidebar marks the
// clicked link with a visual-only `data-pending` accent so the click is acknowledged
// immediately. Throttle the client-side data fetch so the navigation stays pending
// long enough to observe that intermediate state.
await page.goto('/get-started')
await page.getByTestId('product-sidebar').getByText('Start your journey').click()

const sidebar = page.getByTestId('product-sidebar')
const helloWorld = sidebar.getByRole('link', { name: 'Hello World' })
const linkRewriting = sidebar.getByRole('link', { name: 'Link rewriting' })

// Hold the next data request open until we release it, so navigation stays pending.
let releaseNavigation = () => {}
const navigationHeld = new Promise<void>((resolve) => {
releaseNavigation = resolve
})
await page.route('**/_next/data/**', async (route) => {
await navigationHeld
await route.continue()
})

await helloWorld.click()

// While pending: the clicked link carries the optimistic visual marker, but the URL
// and the semantic aria-current still reflect the (still-loaded) get-started page.
await expect(helloWorld).toHaveAttribute('data-pending', '')
await expect(helloWorld).not.toHaveAttribute('aria-current', 'page')
await expect(page).not.toHaveURL(/hello-world/)

// Let the navigation finish: the marker gives way to a real aria-current.
releaseNavigation()
await expect(page).toHaveURL(/\/en\/get-started\/start-your-journey\/hello-world/)
await expect(helloWorld).toHaveAttribute('aria-current', 'page')
await expect(helloWorld).not.toHaveAttribute('data-pending', '')

// A modifier-click (open in new tab) must NOT move the optimistic selection.
// handleNavClick bails on modifier clicks, so pendingHref is never set: the current
// page keeps its URL, its aria-current, and the clicked link gets no data-pending.
// Use ControlOrMeta so the real "open in new tab" modifier is sent per-platform
// (Ctrl on Linux/Windows CI, Meta on macOS). The click opens a background tab we
// don't need to assert on; catch any popup so it doesn't leak.
page.on('popup', (popup) => popup.close())
await linkRewriting.click({ modifiers: ['ControlOrMeta'] })
await expect(linkRewriting).not.toHaveAttribute('data-pending', '')
await expect(helloWorld).toHaveAttribute('aria-current', 'page')
await expect(page).toHaveURL(/\/en\/get-started\/start-your-journey\/hello-world/)
})

test('press "/" to open the search overlay', async ({ page }) => {
await page.goto('/')
await turnOffExperimentsInPage(page)
Expand Down
41 changes: 40 additions & 1 deletion src/landings/components/SidebarProduct.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
// so a top-level article like "Quickstart" gets only the subtle background pill
// and no green bar. Restore the bar for active top-level leaves to match nested
// items. Brand's classes are hashed, so match on the stable substrings.
//
// This also covers `[data-pending]` — the optimistic marker on a just-clicked item
// (see the pending rules below) — so a clicked top-level leaf gets the bar too.
:global([class*="NavList__item--leaf"][class*="NavList__item--level-1"])
:global([class*="NavList__link"])[aria-current]:not(
[aria-current="false"]
)::before {
)::before,
:global([class*="NavList__item--leaf"][class*="NavList__item--level-1"])
:global([class*="NavList__link"])[data-pending]::before {
content: "";
position: absolute;
// Level-1 links are shorter (~24px) than nested leaves, so use a small inset
Expand All @@ -25,4 +30,38 @@
border-radius: var(--base-size-2);
background-color: var(--brand-NavList-activeIndicator-color);
}

// Optimistic "pending" highlight. Article pages are getServerSideProps routes and can
// be slow to load, so router.asPath — and thus aria-current — only updates once the
// page has loaded. We keep aria-current on the *loaded* page (assistive tech must not
// be told a still-loading destination is the current page), and instead mark the
// just-clicked link with `data-pending` for a VISUAL-ONLY accent. Brand couples its
// active styling to `[aria-current]`, so mirror that treatment here for `[data-pending]`.
// data-pending is only set while a *different* page is loading, so it never collides
// with the real aria-current item.
:global([class*="NavList__link"])[data-pending] {
color: var(--brand-color-text-default);
background-color: var(--brand-color-canvas-subtle);
}

// Nested leaves: brand moves the background pill onto the label and adds a leading
// accent bar (mirrors `.item--leaf:not(.item--level-1) .link[aria-current]`).
:global([class*="NavList__item--leaf"]:not([class*="NavList__item--level-1"]))
:global([class*="NavList__link"])[data-pending] {
background-color: transparent;

:global([class*="NavList__labelArea"]) {
background-color: var(--brand-color-canvas-subtle);
}

&::before {
content: "";
position: absolute;
inset-block: var(--base-size-8);
inset-inline-start: 0;
width: var(--base-size-4);
border-radius: var(--base-size-2);
background-color: var(--brand-NavList-activeIndicator-color);
}
}
}
Loading
Loading