Compare commits

...

129 Commits
v2.2.0 ... main

Author SHA1 Message Date
357fea8c37 [汉化] 翻译一些说明和更新日志 2025-05-07 12:00:45 +08:00
85e6279cec Adjust positioning of user email note and permissions heading (#2044)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Licensed / Check licenses (push) Has been cancelled
Build and Test / build (push) Has been cancelled
Build and Test / test (macos-latest) (push) Has been cancelled
Build and Test / test (ubuntu-latest) (push) Has been cancelled
Build and Test / test (windows-latest) (push) Has been cancelled
Build and Test / test-proxy (push) Has been cancelled
Build and Test / test-bypass-proxy (push) Has been cancelled
Build and Test / test-git-container (push) Has been cancelled
Build and Test / test-output (push) Has been cancelled
2025-01-16 15:56:18 -05:00
009b9ae9e4 Documentation update - add recommended permissions to Readme (#2043)
* Update README.md

* Update README.md

Co-authored-by: Josh Gross <joshmgross@github.com>

---------

Co-authored-by: Josh Gross <joshmgross@github.com>
2025-01-16 14:14:48 -05:00
cbb722410c Update README.md (#1977) 2024-11-14 10:41:00 -05:00
3b9b8c884f docs: update README.md (#1971)
Add a scenario where it is necessary to push a commit to a pull request.
2024-11-08 10:32:54 -05:00
11bd71901b Prepare 4.2.2 Release (#1953)
* Prepare 4.2.2 Release

---------

Co-authored-by: Josh Gross <joshmgross@github.com>
2024-10-23 16:24:28 +02:00
e3d2460bbb Expand unit test coverage (#1946) 2024-10-23 15:59:08 +02:00
163217dfcd url-helper.ts now leverages well-known environment variables. (#1941)
* `utl-helper.ts` now leverages well-known environment variables.

---------
Co-authored-by: Erez Testiler <easyt@github.com>
2024-10-18 10:07:17 +02:00
eef61447b9 Prepare 4.2.1 release (#1925) 2024-10-07 12:38:04 -04:00
6b42224f41 Add workflow file for publishing releases to immutable action package (#1919)
This workflow file publishes new action releases to the immutable action package of the same name as this repo.

This is part of the Immutable Actions project which is not yet fully released to the public. First party actions like this one are part of our initial testing of this feature.
2024-10-03 11:03:35 +02:00
de5a000abf Check out other refs/* by commit if provided, fall back to ref (#1924) 2024-10-01 20:24:28 -04:00
d632683dd7 Prepare 4.2.0 release (#1878)
* Bump package version to 4.1.8

* Add v4.1.8 changelog

* Bump version to `4.2.0`
2024-09-25 13:51:15 -04:00
6d193bf280 Bump braces from 3.0.2 to 3.0.3 (#1777)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-05 15:04:42 -04:00
db0cee9a51 Bump the minor-npm-dependencies group across 1 directory with 4 updates (#1872)
* Bump the minor-npm-dependencies group across 1 directory with 4 updates

Bumps the minor-npm-dependencies group with 4 updates in the / directory: [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest), [prettier](https://github.com/prettier/prettier), [ts-jest](https://github.com/kulshekhar/ts-jest) and [typescript](https://github.com/Microsoft/TypeScript).


Updates `eslint-plugin-jest` from 28.5.0 to 28.8.2
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.5.0...v28.8.2)

Updates `prettier` from 3.2.5 to 3.3.3
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.2.5...3.3.3)

Updates `ts-jest` from 29.1.2 to 29.2.5
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.1.2...v29.2.5)

Updates `typescript` from 5.4.5 to 5.5.4
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.4.5...v5.5.4)

---
updated-dependencies:
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
- dependency-name: ts-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* `npm run build`

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Gross <joshmgross@github.com>
2024-09-05 15:04:17 -04:00
b684943689 Add Ref and Commit outputs (#1180)
Signed-off-by: Luca Comellini <luca.com@gmail.com>
2024-09-05 11:57:13 -04:00
2d7d9f7ff5 Provide explanation for where user email came from (#1869)
* Provide explanation for where user email came from

* bringing back the newline
2024-09-02 09:53:38 -04:00
9a9194f871 Bump docker/build-push-action from 5.3.0 to 6.5.0 (#1832)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.3.0 to 6.5.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5.3.0...v6.5.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 16:10:36 -04:00
dd960bd3c3 Bump docker/login-action in the minor-actions-dependencies group (#1831)
Bumps the minor-actions-dependencies group with 1 update: [docker/login-action](https://github.com/docker/login-action).


Updates `docker/login-action` from 3.1.0 to 3.3.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.1.0...v3.3.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-actions-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 16:10:02 -04:00
692973e3d9 Prepare 4.1.7 release (#1775)
* Prepare 4.1.7 release

* Include #1776 in 4.1.7 release
2024-06-12 14:41:43 -04:00
6ccd57f4c5 Pin actions/checkout's own workflows to a known, good, stable version. (#1776)
* Pin actions/checkout's own workflows to a known, good, stable version.

* fixed failing unit test

* fix unit test
2024-06-12 13:11:03 -04:00
b17fe1e4d5 Handle hidden refs (#1774)
Co-authored-by: Chris Gavin <chris@chrisgavin.me>
2024-06-12 11:01:40 -04:00
b80ff79f17 Bump actions/checkout from 3 to 4 (#1697)
* Bump actions/checkout from 3 to 4

Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* Apply suggestions from code review

* .

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2024-05-20 14:25:59 -04:00
b1ec3021b8 Bump the minor-npm-dependencies group across 1 directory with 4 updates (#1739)
Bumps the minor-npm-dependencies group with 4 updates in the / directory: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest).


Updates `@types/node` from 20.12.7 to 20.12.12
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@typescript-eslint/eslint-plugin` from 7.7.1 to 7.9.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.9.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 7.7.1 to 7.9.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v7.9.0/packages/parser)

Updates `eslint-plugin-jest` from 28.2.0 to 28.5.0
- [Release notes](https://github.com/jest-community/eslint-plugin-jest/releases)
- [Changelog](https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jest-community/eslint-plugin-jest/compare/v28.2.0...v28.5.0)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor-npm-dependencies
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
- dependency-name: eslint-plugin-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-npm-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 09:56:19 -04:00
a5ac7e51b4 Update for 4.1.6 release (#1733) 2024-05-16 14:08:36 -04:00
24ed1a3528 Check platform for extension (#1732) 2024-05-16 13:40:36 -04:00
44c2b7a8a4 README: Suggest user.email to be 41898282+github-actions[bot]@users.noreply.github.com (#1707)
* README: Set `user.email` to GitHub Actions Bot

* Update workflow to use proper bot GitHub Bot email

* Prefix `user.email` with `41898282+`

To match squash merge user, else showing as two different users, see: b0948d0da0

* Update README.md

---------

Co-authored-by: Pelle Wessman <pelle@kodfabrik.se>
2024-04-30 11:50:54 -04:00
8459bc0c7e Bump actions/upload-artifact from 2 to 4 (#1695)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-24 12:39:59 -04:00
3f603f6d5e Bump actions/setup-node from 1 to 4 (#1696)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 1 to 4.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v1...v4)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-24 12:34:46 -04:00
fd084cde18 Bump github/codeql-action from 2 to 3 (#1694)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-24 12:33:41 -04:00
9c1e94e0ad Update NPM dependencies (#1703)
* Update dependencies manually
* Format files
* Update licenses
2024-04-24 12:04:10 -04:00
0ad4b8fada Prep Release v4.1.4 (#1704)
* Update package.json and package-lock.json to reflect v4.1.4
* Update CHANGELOG
2024-04-24 15:29:05 +02:00
43045ae669 Disable extensions.worktreeConfig when disabling sparse-checkout (#1692) 2024-04-23 22:07:43 +02:00
37b082107b Bump the minor-actions-dependencies group with 2 updates (#1693)
Bumps the minor-actions-dependencies group with 2 updates: [docker/login-action](https://github.com/docker/login-action) and [docker/build-push-action](https://github.com/docker/build-push-action).


Updates `docker/login-action` from 3.0.0 to 3.1.0
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.0.0...v3.1.0)

Updates `docker/build-push-action` from 5.1.0 to 5.3.0
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5.1.0...v5.3.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-actions-dependencies
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-actions-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 13:14:23 -04:00
9839dc14a0 Add dependabot config (#1688)
* Add dependabot config
* Group minor and patch updates for NPM and GH Actions
2024-04-23 13:02:51 -04:00
9b4c13b0bf Bump word-wrap from 1.2.3 to 1.2.5 (#1643)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.5.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.5)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 12:52:06 +02:00
1d96c772d1 Add SSH user parameter (#1685)
* Add a configurable SSH user

* Update docs with param

* Indentation of readme

* formatting woes

* Update src/url-helper.ts

Co-authored-by: Josh Gross <joshmgross@github.com>

* Update action.yml

Co-authored-by: Josh Gross <joshmgross@github.com>

* Update genfiles

---------

Co-authored-by: Josh Gross <joshmgross@github.com>
2024-04-18 15:29:55 -04:00
cd7d8d697e Check git version before attempting to disable sparse-checkout (#1656)
* Check git version before attempting to disable `sparse-checkout`
* Bump `MinimumGitSparseCheckoutVersion` to 2.28 due to #1386
* Initial prep for release 4.1.3
2024-03-14 15:40:14 +01:00
8410ad0602 Update actions/checkout version in update-main-version.yml (#1650) 2024-03-12 12:39:30 +01:00
9bb56186c3 Prep for release of v4.1.2 (#1649)
* Add v4.1.2 and v4.1.1 to CHANGELOG.md
* Bump version in package.json to 4.1.2
* Ran `npm i` to regenerate package-lock.json
2024-03-12 12:11:01 +01:00
8eb1f6a495 Bump @babel/traverse from 7.20.5 to 7.24.0 (#1642)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.20.5 to 7.24.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.0/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 13:09:59 -05:00
556e4c3cb0 Bump tough-cookie from 4.0.0 to 4.1.3 (#1406)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.0.0 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.0.0...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 12:49:25 -05:00
b32f140b0c Warn on attempts to publish test-ubuntu-git from non-main branch. (#1623)
* Warn on attempts to publish test-ubuntu-git from non-main branch.
* Rename build step to clarify that Push is optional.
2024-02-22 14:38:58 +01:00
2650dbd060 Give test-ubuntu-git its own README (#1620)
* Give `test-ubuntu-git` its own `README`
* Refined title and description in `test-ubuntu-git.Dockerfile`
* nit accepted:  Remove double space

---------

Co-authored-by: Ferenc Hammerl <31069338+fhammerl@users.noreply.github.com>
2024-02-22 10:59:35 +01:00
aadec89964 Explicitly disable sparse checkout unless asked for (#1598)
When a worktree is reused by actions/checkout and the first time sparse checkout was enabled, we need to ensure that the second time it is only a sparse checkout if explicitly asked for. Otherwise, we need to disable the sparse checkout so that a full checkout is the outcome of this Action.

## Details
* If no `sparse-checkout` parameter is specified, disable it

This should allow users to reuse existing folders when running
`actions/checkout` where a previous run asked for a sparse checkout but
the current run does not ask for a sparse checkout.

This fixes https://github.com/actions/checkout/issues/1475

There are use cases in particular with non-ephemeral (self-hosted) runners where an
existing worktree (that has been initialized as a sparse checkout) is
reused in subsequent CI runs (where `actions/checkout` is run _without_
any `sparse-checkout` parameter).

In these scenarios, we need to make sure that the sparse checkout is
disabled before checking out the files.

### Also includes:

* npm run build
* ci: verify that an existing sparse checkout can be made unsparse
* Added a clarifying comment about test branches.
* `test-proxy` now uses newly-minted `test-ubuntu-git` container image from ghcr.io

---------

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Co-authored-by: John Wesley Walker III <81404201+jww3@users.noreply.github.com>
2024-02-21 13:56:19 +01:00
df0bcddf6d Refine workflow for generating test-ubuntu-git (#1617) 2024-02-21 12:46:47 +01:00
473055ba18 Create test-ubuntu-git Docker Container for Proxy Tests (#1616) 2024-02-20 17:08:08 +01:00
b4ffde65f4 Link to release page from what's new section (#1514) 2023-10-17 11:52:30 -04:00
8530928916 Correct link to GitHub Docs (#1511)
No hardcoded language in the URL and uses the correct docs.github.com domain.
2023-10-13 11:07:47 -04:00
7cdaf2fbc0 Update CODEOWNERS to Launch team (#1510) 2023-10-10 11:16:51 -04:00
8ade135a41 Prepare 4.1.0 release (#1496) 2023-09-22 13:40:21 -04:00
c533a0a4cf Add support for partial checkout filters (#1396)
* added filter option & tests

* added build file

* fix test oversight

* added exit 1

* updated docs to specify override

* undo unneeded readme change

* set to undefined rather than empty string

* run git config in correct di

---------

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2023-09-22 13:30:36 -04:00
72f2cec99f Update README.md for V4 (#1452)
* Update README.md for V4

* Update actionReference in generate-docs.ts for v4
2023-09-05 09:21:52 -04:00
3df4ab11eb Release 4.0.0 (#1447)
* Release 4.0.0

* Add new major version to workflow
2023-09-04 14:19:40 +02:00
8b5e8b7687 Support fetching without the --progress option (#1067)
Setting the `show-progress` option to false in the `with` section of the
workflow step will cause git fetch to run without `--progress`.

The motivation is to be able to suppress the noisy progress status
output which adds many hundreds of "remote: Counting objects: 85%
(386/453)" and similar lines in the workflow log.

This should be sufficient to resolve #894 and its older friends,
though the solution is different to the one proposed there because
it doesn't use the --quiet flag. IIUC git doesn't show the progress
status by default since the output is not a terminal, so that's why
removing the --progress option is all that's needed.

Adding the --quiet flag doesn't make a lot of difference once the
--progress flag is removed, and actually I think using --quiet would
suppress some other more useful output that would be better left
visible.

Signed-off-by: Simon Baird <sbaird@redhat.com>
2023-09-01 14:19:18 -04:00
97a652b800 Update default runtime to node20 (#1436)
* .

* update workflows
2023-08-29 17:01:52 +02:00
f43a0e5ff2 Release 3.6.0 (#1437) 2023-08-24 09:54:47 -04:00
7739b9ba2e Add option to fetch tags even if fetch-depth > 0 (#579)
* Add option to fetch tags even if fetch-depth > 0

* Add jest tests for fetchDepth and fetchTags options
2023-08-16 16:34:54 -04:00
96f53100ba Mark test scripts with Bash'isms to be run via Bash (#1377)
In #1369, I mistakenly replaced the hash-bang lines in the two new
scripts with `#!/bin/sh`, missing that both files contain the Bash'ism
`[[`. Symptom as per
https://github.com/actions/checkout/actions/runs/5200323109/jobs/9378889172?pr=1369#step:12:5

    __test__/verify-sparse-checkout.sh: 58: [[: not found

Let's change those hash-bang lines back to `#!/bin/bash`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2023-06-09 11:05:29 -04:00
c85c95e3d7 Release v3.5.3 (#1376) 2023-06-09 10:47:54 -04:00
d106d4669b Add support for sparse checkouts (#1369)
* Add support for sparse checkouts

* sparse-checkout: optionally turn off cone mode

While it _is_ true that cone mode is the default nowadays (mainly for
performance reasons: code mode is much faster than non-cone mode), there
_are_ legitimate use cases where non-cone mode is really useful.

Let's add a flag to optionally disable cone mode.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Verify minimum Git version for sparse checkout

The `git sparse-checkout` command is available only since Git version
v2.25.0. The `actions/checkout` Action actually supports older Git
versions than that; As of time of writing, the minimum version is
v2.18.0.

Instead of raising this minimum version even for users who do not
require a sparse checkout, only check for this minimum version
specifically when a sparse checkout was asked for.

Suggested-by: Tingluo Huang <tingluohuang@github.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Support sparse checkout/LFS better

Instead of fetching all the LFS objects present in the current revision
in a sparse checkout, whether they are needed inside the sparse cone or
not, let's instead only pull the ones that are actually needed.

To do that, let's avoid running that preemptive `git lfs fetch` call in
case of a sparse checkout.

An alternative that was considered during the development of this patch
(and ultimately rejected) was to use `git lfs pull --include <path>...`,
but it turned out to be too inflexible because it requires exact paths,
not the patterns that are available via the sparse checkout definition,
and that risks running into command-line length limitations.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

---------

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Co-authored-by: Daniel <daniel.fernandez@feverup.com>
2023-06-09 09:08:21 -04:00
f095bcc56b Fix typos found by codespell (#1287) 2023-04-19 16:55:10 +02:00
SKi
47fbe2df0a Fix: Checkout fail in self-hosted runners when faulty submodule are checked-in (#1196)
* Fix Self hosted runner issue wrt bad submodules - solution cleanup working space.

* Fix format with npm run format output

* Add mock implementation for new function submoduleStatus

* Add 2  test cases for submodule status.

* Codeql-Action Analyse revert v1 to v2

---------

Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com>
Co-authored-by: sminnie <minnie@sankhe.com>
2023-04-14 06:26:47 -04:00
8e5e7e5ab8 Release v3.5.2 (#1291)
* Update version and changelog for 3.5.2

* Update changelog
2023-04-13 14:45:33 +02:00
eb35239ec2 Fix: convert baseUrl to serverApiUrl 'formatted' (#1289)
* fix: convert baseUrl to apiUrl

* Run prettier

---------

Co-authored-by: 1newsr <1newsr@users.noreply.github.com>
2023-04-13 14:25:50 +02:00
83b7061638 Release v3.5.1 (#1284)
* Sync checkout version with tag version

* Downgrade to 3.5.1

* Format changelog
2023-04-12 17:02:21 +02:00
40a16ebeed Improve checkout performance on Windows runners by upgrading @actions/github dependency (#1246)
* Improve checkout performance on Windows runners by upgrading @actions/github dependency

Re: https://github.com/actions/checkout/issues/1186

@dscho discovered that the checkout action could stall for a
considerable amount of time on Windows runners waiting for PowerShell
invocations made from 'windows-release' npm package to complete.

Then I studied the dependency chain to figure out where
'windows-release' was imported:

'@actions/checkout'@main
  <- '@actions/github'@2.2.0
    <- '@octokit/endpoint'@6.0.1
    <- '@octokit/graphql'@4.3.1
    <- '@octokit/request'@5.4.2
    <- '@octokit/rest'@16.43.1
      <- 'universal-user-agent'@4.0.1
        <- 'os-name'@3.1.0
          <- 'windows-release'@3.1.0

'universal-user-agent' package dropped its dependency on 'os-name' in
https://github.com/gr2m/universal-user-agent/releases/tag/v6.0.0 .

'@actions/github' v3 removed dependency on '@octokit/rest'@16.43.1 and
allows users to move away from the old 'universal-user-agent' v4.
(https://github.com/actions/toolkit/pull/453)

This pull request attempts to update the version of '@actions/github'
used in the checkout action to avoid importing 'windows-release'.

Based on testing in my own repositories, I can see an improvement in
reduced wait time between entering the checkout action and git actually
starts to do useful work.

* Update .licenses

* Rebuild index.js
2023-04-12 13:55:27 +02:00
8f4b7f8486 Add new public key for known_hosts (#1237)
* Add new public key for known_hosts

* Fix the build!
2023-03-24 01:34:48 -04:00
cd6a9fd493 Update update-main-version.yml 2023-03-23 22:44:49 -04:00
24cb908017 Bump @actions/io to v1.1.3 (#1225)
* Backfill changelog and bump actions/io
* Fill in PR for action/io upgrade
* Licensed updates
* Compile JS
2023-03-15 15:45:08 -04:00
27135e314d Upgrade dependencies (#1210)
* Upgrade ncc & json5

* Add new dist build
2023-03-09 11:42:29 -05:00
7b187184d1 Upgrade codeql actions to v2 (#1209) 2023-03-09 10:59:09 -05:00
ac59398561 Fix comment typos (that got added in #770) (#1057) 2022-12-28 17:19:08 -05:00
3ba5ee6fac Add in explicit reference to private checkout options (#1050) 2022-12-16 16:06:54 -05:00
8856415920 Implement branch list using callbacks from exec function (#1045)
When trying to list local branches to figure out what needs cleaned up during runs on non-ephemeral Actions Runners, we use git rev-parse --symbolic-full-name to get a list of branches. This can lead to ambiguous ref name errors when there are branches and tags with similar names.

Part of the reason we use rev-parse --symbolic-full-name vs git branch --list or git rev-parse --symbolic seems to related to a bug in Git 2.18. Until we can deprecate our usage of Git 2.18, I think we need to keep --symbolic-full-name. Since part of the problem is that these ambiguous ref name errors clog the Actions annotation limits, this is a mitigation to suppress those messages until we can get rid of the workaround.
2022-12-14 16:08:53 -05:00
755da8c3cf 3.2.0 (#1039) 2022-12-12 14:11:05 -05:00
26d48e8ea1 Update @actions/io to 1.1.2 (#1029) 2022-12-12 13:44:24 -05:00
Jok
bf085276ce wrap pipeline commands for submoduleForeach in quotes (#964)
* wrap pipeline commands for submoduleForeach in quotes

* Update src/git-auth-helper.ts

drop extraneous space.

Co-authored-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* Followed CONTRIBUTING.md instructions, updating dist/index.js

* fixed package-lock.json

* updating the pipeline so it runs from sh

Co-authored-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2022-11-15 21:51:19 -05:00
5c3ccc22eb Replace datadog/squid with ubuntu/squid Docker image (#1002)
* test with ubuntu/squid

* Start a contributing guide

* remove link
2022-11-10 15:54:12 -05:00
1f9a0c22da README - fix status badge (#967) 2022-10-17 09:49:29 -04:00
8230315d06 Add workflow to update a main version (#942)
* Add workflow to update a main version

* New line
2022-10-04 13:44:41 +01:00
93ea575cb5 Prepare release v3.1.0 (#940)
* Prepare changelog for v3.1.0

* Bump package
2022-10-04 10:37:06 +01:00
6a84743051 Bump @actions/core to 1.10.0 (#939)
* Bump @actions/core to 1.10.0

* Update licenses

* Use @actions/core helper functions
2022-10-03 18:04:49 +01:00
e6d535c99c Inject GitHub host to be able to clone from another GitHub instance (#922)
* Adding the ability to specify the GitHub Server URL and allowing for it to differ from the Actions workflow host

* Adding tests for injecting the GitHub URL

* Addressing code review comments for PR #922
2022-09-26 12:34:52 -04:00
2541b1294d Prepare changelog for v3.0.2. (#777) 2022-04-21 10:29:04 -04:00
0ffe6f9c55 Add set-safe-directory input to allow customers to take control. (#770)
* Add set-safe-directory input to allow customers to take control.
2022-04-20 21:37:43 -04:00
dcd71f6466 Enforce safe directory (#762)
* set safe directory when running checkout

* Update CHANGELOG.md
2022-04-14 14:13:20 -04:00
add3486cc3 Patch to fix the dependbot alert. (#744)
* Patch to fix the dependbot alert.

* .

* .

* .
2022-04-05 13:01:33 -04:00
5126516654 Bump minimist from 1.2.5 to 1.2.6 (#741)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-31 10:09:15 -04:00
d50f8ea767 Add v3.0 release information to changelog (#740) 2022-03-25 09:52:31 -04:00
2d1c1198e7 update test workflows to checkout v3 (#709) 2022-03-01 13:02:13 -05:00
a12a3943b4 update readme for v3 (#708)
* update readme for v3

* update readme with changes

* nit grammar
2022-03-01 12:46:45 -05:00
8f9e05e482 Update to node 16 (#689)
* Update to node 16

* update setup-node version

* Update check-dist.yml

update setup node version

* update dist/index.js
2022-02-28 16:17:29 -05:00
230611dbd0 Change secret name for PAT to not start with GITHUB_ (#623)
Github doesn't allow secret names that start with `GITHUB_` (case insensitive). Update README to choose a different prefix (GH).
2021-11-02 16:20:59 -05:00
ec3a7ce113 set insteadOf url for org-id (#621) 2021-11-01 11:43:18 -05:00
fd47087372 codeql should analyze lib not dist (#620) 2021-10-20 15:11:24 -05:00
3d677ac575 script to generate license info (#614) 2021-10-19 14:30:04 -05:00
826ba42d6c npm audit fix (#612) 2021-10-19 10:05:28 -05:00
eb8a193c1d update dev dependencies and react to new linting rules (#611) 2021-10-19 09:52:57 -05:00
c49af7ca1f Create codeql-analysis.yml (#602) 2021-10-18 16:28:25 -05:00
1e204e9a92 update licensed check (#606) 2021-10-13 16:22:03 -05:00
0299a0d2b6 update dist (#605) 2021-10-13 16:07:05 -05:00
be0f448456 Bump ws from 5.2.2 to 5.2.3 (#604)
Bumps [ws](https://github.com/websockets/ws) from 5.2.2 to 5.2.3.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.2...5.2.3)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:14:20 -05:00
56c00a7b1f Bump tmpl from 1.0.4 to 1.0.5 (#588)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:13:31 -05:00
85e47d1a2b Bump path-parse from 1.0.6 to 1.0.7 (#568)
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:13:04 -05:00
3fc17f8645 Bump hosted-git-info from 2.8.5 to 2.8.9 (#500)
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.5 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.5...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:11:06 -05:00
e3bc06d986 Bump lodash from 4.17.15 to 4.17.21 (#499)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:08:31 -05:00
442567ba57 Bump handlebars from 4.5.3 to 4.7.7 (#497)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.5.3 to 4.7.7.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.5.3...v4.7.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:07:45 -05:00
7f00b66d06 Bump y18n from 4.0.0 to 4.0.1 (#469)
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 09:07:05 -05:00
eccf386318 Bump @actions/core from 1.1.3 to 1.2.6 (#361)
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.1.3 to 1.2.6.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 08:57:33 -05:00
2bd2911be9 Bump acorn from 5.7.3 to 5.7.4 (#186)
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-13 08:55:25 -05:00
afe4af09a7 Create check-dist.yml (#566)
* Add check-dist.yml

* Don't need to mv to git diff

* Upload the whole dist/ directory as an artifact

* Update .github/workflows/check-dist.yml
2021-08-17 16:08:22 -04:00
25a956c84d Create CODEOWNERS 2021-02-04 12:25:41 -05:00
5a4ac9002d Add missing awaits (#379)
* auth-helper: properly await replacement of the token value in the config

After writing the `.extraheader` config, we manually replace the token
with the actual value. This is done in an `async` function, but we were
not `await`ing the result.

In our tests, this commit fixes a flakiness we observed where
`remote.origin.url` sometimes (very rarely, actually) is not set for
submodules. Our interpretation is that the configs are in the process of
being rewritten with the correct token value _while_ another `git
config` that wants to set the `insteadOf` value is reading the config,
which is currently empty.

A more idiomatic way to fix this in Typescript would use
`Promise.all()`, like this:

      await Promise.all(
        configPaths.map(async configPath => {
          core.debug(`Replacing token placeholder in '${configPath}'`)
          await this.replaceTokenPlaceholder(configPath)
        })
      )

However, during review of https://github.com/actions/checkout/pull/379
it was decided to keep the `for` loop in the interest of simplicity.

Reported by Ian Lynagh.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* downloadRepository(): await the result of recursive deletions

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Ask ESLint to report floating Promises

This rule is quite helpful in avoiding hard-to-debug missing `await`s.

Note: there are two locations in `src/main.ts` that trigger warnings:
the `run()` and the `cleanup()` function are called without `await` and
without any `.catch()` clause.

In the initial version of https://github.com/actions/checkout/pull/379,
this was addressed by adding `.catch()` clauses. However, it was
determined that this is boilerplate code that will need to be fixed in a
broader way.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

* Rebuild

This trick was brought to you by `npm ci && npm run build`. Needed to
get the PR build to pass.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2020-11-03 09:44:09 -05:00
c952173edf Swap to Environment Files (#360) 2020-09-30 11:41:09 -04:00
a81bbbf829 Remove unneeded commit information from build logs (#345)
* Remove unneeded commit information from stdout
2020-09-23 09:41:47 -04:00
21dc310f19 Add Licensed To Help Verify Prod Licenses (#326)
* Add Licensed file and workflow

* manual updates of dependencies

* Delete licenses.txt

* Ignore Generated Files in Git PR's
2020-09-10 09:24:29 -04:00
be6c44d969 Revert "Delete licenses.txt" 2020-08-11 19:41:01 -04:00
dac8cc78a1 Delete licenses.txt 2020-08-11 19:36:35 -04:00
2036a08e25 Add Third Party License Information to Dist Files (#320) 2020-08-07 09:22:39 -04:00
592cf69a22 Update README.md 2020-07-14 16:30:57 -04:00
a4b69b4886 Update README.md 2020-07-14 13:08:52 -04:00
1433f62caa update default branch (#305) 2020-07-14 09:23:30 -04:00
61b9e3751b improve description for fetch-depth (#301) 2020-07-12 21:02:24 -04:00
28c7f3d2b5 changelog 2020-06-18 10:27:39 -04:00
fb6f360df2 fix default branch for .wiki and when using ssh (#284) 2020-06-18 10:20:33 -04:00
b4483adec3 changelog 2020-06-16 13:48:53 -04:00
00a3be8934 determine default branch (#278) 2020-06-16 13:41:01 -04:00
453ee27fca update troubleshooting instructions to include 'npm run format' 2020-05-31 17:48:51 -04:00
65865e15a1 build because all is no more (#264) 2020-05-31 17:46:53 -04:00
88 changed files with 45376 additions and 35241 deletions

View File

@ -1,6 +1,6 @@
{
"plugins": ["jest", "@typescript-eslint"],
"extends": ["plugin:github/es6"],
"extends": ["plugin:github/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
@ -16,23 +16,19 @@
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-ignore": "error",
"camelcase": "off",
"@typescript-eslint/camelcase": "error",
"@typescript-eslint/class-name-casing": "error",
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-object-literal-type-assertion": "error",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
@ -40,7 +36,6 @@
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-interface": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
.licenses/** -diff linguist-generated=true

20
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,20 @@
---
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
groups:
minor-npm-dependencies:
# NPM: Only group minor and patch updates (we want to carefully review major updates)
update-types: [minor, patch]
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
minor-actions-dependencies:
# GitHub Actions: Only group minor and patch updates (we want to carefully review major updates)
update-types: [minor, patch]

51
.github/workflows/check-dist.yml vendored Normal file
View File

@ -0,0 +1,51 @@
# `dist/index.js` is a special file in Actions.
# When you reference an action with `uses:` in a workflow,
# `index.js` is the code that will run.
# For our project, we generate this file through a build process
# from other source files.
# We need to make sure the checked-in `index.js` actually matches what we expect it to be.
name: Check dist
on:
push:
branches:
- main
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
workflow_dispatch:
jobs:
check-dist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.6
- name: Set Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install dependencies
run: npm ci
- name: Rebuild the index.js file
run: npm run build
- name: Compare the expected and actual dist/ directories
run: |
if [ "$(git diff --ignore-space-at-eol dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff
exit 1
fi
# If dist/ was different than expected, upload the expected version as an artifact
- uses: actions/upload-artifact@v4
if: ${{ failure() && steps.diff.conclusion == 'failure' }}
with:
name: dist
path: dist/

58
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,58 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '28 9 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v4.1.6
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- run: npm ci
- run: npm run build
- run: rm -rf dist # We want code scanning to analyze lib instead (individual .js files)
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

14
.github/workflows/licensed.yml vendored Normal file
View File

@ -0,0 +1,14 @@
name: Licensed
on:
push: {branches: main}
pull_request: {branches: main}
jobs:
test:
runs-on: ubuntu-latest
name: Check licenses
steps:
- uses: actions/checkout@v4.1.6
- run: npm ci
- run: npm run licensed-check

View File

@ -0,0 +1,20 @@
name: 'Publish Immutable Action Version'
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
steps:
- name: Checking out
uses: actions/checkout@v4
- name: Publish
id: publish
uses: actions/publish-immutable-action@0.0.3

View File

@ -4,17 +4,22 @@ on:
pull_request:
push:
branches:
- master
- main
- releases/*
# Note that when you see patterns like "ref: test-data/v2/basic" within this workflow,
# these refer to "test-data" branches on this actions/checkout repo.
# (For example, test-data/v2/basic -> https://github.com/actions/checkout/tree/test-data/v2/basic)
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v1
- uses: actions/setup-node@v4
with:
node-version: 12.x
- uses: actions/checkout@v2
node-version: 20.x
- uses: actions/checkout@v4.1.6
- run: npm ci
- run: npm run build
- run: npm run format-check
@ -32,7 +37,7 @@ jobs:
steps:
# Clone this repo
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4.1.6
# Basic checkout
- name: Checkout basic
@ -72,6 +77,53 @@ jobs:
shell: bash
run: __test__/verify-side-by-side.sh
# Filter
- name: Fetch filter
uses: ./
with:
filter: 'blob:none'
path: fetch-filter
- name: Verify fetch filter
run: __test__/verify-fetch-filter.sh
# Sparse checkout
- name: Sparse checkout
uses: ./
with:
sparse-checkout: |
__test__
.github
dist
path: sparse-checkout
- name: Verify sparse checkout
run: __test__/verify-sparse-checkout.sh
# Disabled sparse checkout in existing checkout
- name: Disabled sparse checkout
uses: ./
with:
path: sparse-checkout
- name: Verify disabled sparse checkout
shell: bash
run: set -x && ls -l sparse-checkout/src/git-command-manager.ts
# Sparse checkout (non-cone mode)
- name: Sparse checkout (non-cone mode)
uses: ./
with:
sparse-checkout: |
/__test__/
/.github/
/dist/
sparse-checkout-cone-mode: false
path: sparse-checkout-non-cone-mode
- name: Verify sparse checkout (non-cone mode)
run: __test__/verify-sparse-checkout-non-cone-mode.sh
# LFS
- name: Checkout LFS
uses: ./
@ -138,11 +190,11 @@ jobs:
test-proxy:
runs-on: ubuntu-latest
container:
image: alpine/git:latest
image: ghcr.io/actions/test-ubuntu-git:main.20240221.114913.703z
options: --dns 127.0.0.1
services:
squid-proxy:
image: datadog/squid:latest
image: ubuntu/squid:latest
ports:
- 3128:3128
env:
@ -150,7 +202,7 @@ jobs:
steps:
# Clone this repo
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4.1.6
# Basic checkout using git
- name: Checkout basic
@ -182,7 +234,7 @@ jobs:
steps:
# Clone this repo
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4.1.6
# Basic checkout using git
- name: Checkout basic
@ -205,3 +257,75 @@ jobs:
path: basic
- name: Verify basic
run: __test__/verify-basic.sh --archive
test-git-container:
runs-on: ubuntu-latest
container: bitnami/git:latest
steps:
# Clone this repo
- name: Checkout
uses: actions/checkout@v4.1.6
with:
path: localClone
# Basic checkout using git
- name: Checkout basic
uses: ./localClone
with:
ref: test-data/v2/basic
- name: Verify basic
run: |
if [ ! -f "./basic-file.txt" ]; then
echo "Expected basic file does not exist"
exit 1
fi
# Verify .git folder
if [ ! -d "./.git" ]; then
echo "Expected ./.git folder to exist"
exit 1
fi
# Verify auth token
git config --global --add safe.directory "*"
git fetch --no-tags --depth=1 origin +refs/heads/main:refs/remotes/origin/main
# needed to make checkout post cleanup succeed
- name: Fix Checkout v4
uses: actions/checkout@v4.1.6
with:
path: localClone
test-output:
runs-on: ubuntu-latest
steps:
# Clone this repo
- name: Checkout
uses: actions/checkout@v4.1.6
# Basic checkout using git
- name: Checkout basic
id: checkout
uses: ./
with:
ref: test-data/v2/basic
# Verify output
- name: Verify output
run: |
echo "Commit: ${{ steps.checkout.outputs.commit }}"
echo "Ref: ${{ steps.checkout.outputs.ref }}"
if [ "${{ steps.checkout.outputs.ref }}" != "test-data/v2/basic" ]; then
echo "Expected ref to be test-data/v2/basic"
exit 1
fi
if [ "${{ steps.checkout.outputs.commit }}" != "82f71901cf8c021332310dcc8cdba84c4193ff5d" ]; then
echo "Expected commit to be 82f71901cf8c021332310dcc8cdba84c4193ff5d"
exit 1
fi
# needed to make checkout post cleanup succeed
- name: Fix Checkout
uses: actions/checkout@v4.1.6

View File

@ -0,0 +1,35 @@
name: Update Main Version
run-name: Move ${{ github.event.inputs.major_version }} to ${{ github.event.inputs.target }}
on:
workflow_dispatch:
inputs:
target:
description: The tag or reference to use
required: true
major_version:
type: choice
description: The major version to update
options:
- v4
- v3
- v2
jobs:
tag:
runs-on: ubuntu-latest
steps:
# Note this update workflow can also be used as a rollback tool.
# For that reason, it's best to pin `actions/checkout` to a known, stable version
# (typically, about two releases back).
- uses: actions/checkout@v4.1.6
with:
fetch-depth: 0
- name: Git config
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Tag new target
run: git tag -f ${{ github.event.inputs.major_version }} ${{ github.event.inputs.target }}
- name: Push new tag
run: git push origin ${{ github.event.inputs.major_version }} --force

View File

@ -0,0 +1,59 @@
name: Publish test-ubuntu-git Container
on:
# Use an on demand workflow trigger.
# (Forked copies of actions/checkout won't have permission to update GHCR.io/actions,
# so avoid trigger events that run automatically.)
workflow_dispatch:
inputs:
publish:
description: 'Publish to ghcr.io? (main branch only)'
type: boolean
required: true
default: false
env:
REGISTRY: ghcr.io
IMAGE_NAME: actions/test-ubuntu-git
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Use `docker/login-action` to log in to GHCR.io.
# Once published, the packages are scoped to the account defined here.
- name: Log in to the ghcr.io container registry
uses: docker/login-action@v3.3.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Format Timestamp
id: timestamp
# Use `date` with a custom format to achieve the key=value format GITHUB_OUTPUT expects.
run: date -u "+now=%Y%m%d.%H%M%S.%3NZ" >> "$GITHUB_OUTPUT"
- name: Issue Image Publish Warning
if: ${{ inputs.publish && github.ref_name != 'main' }}
run: echo "::warning::test-ubuntu-git images can only be published from the actions/checkout 'main' branch. Workflow will continue with push/publish disabled."
# Use `docker/build-push-action` to build (and optionally publish) the image.
- name: Build Docker Image (with optional Push)
uses: docker/build-push-action@v6.5.0
with:
context: .
file: images/test-ubuntu-git.Dockerfile
# For now, attempts to push to ghcr.io must target the `main` branch.
# In the future, consider also allowing attempts from `releases/*` branches.
push: ${{ inputs.publish && github.ref_name == 'main' }}
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}.${{ steps.timestamp.outputs.now }}

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
__test__/_temp
_temp/
lib/
node_modules/
node_modules/
.vscode/

14
.licensed.yml Normal file
View File

@ -0,0 +1,14 @@
sources:
npm: true
allowed:
- apache-2.0
- bsd-2-clause
- bsd-3-clause
- isc
- mit
- cc0-1.0
- unlicense
reviewed:
npm:

20
.licenses/npm/@actions/core.dep.yml generated Normal file
View File

@ -0,0 +1,20 @@
---
name: "@actions/core"
version: 1.10.1
type: npm
summary: Actions core lib
homepage: https://github.com/actions/toolkit/tree/main/packages/core
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

20
.licenses/npm/@actions/exec.dep.yml generated Normal file
View File

@ -0,0 +1,20 @@
---
name: "@actions/exec"
version: 1.1.1
type: npm
summary: Actions exec lib
homepage: https://github.com/actions/toolkit/tree/main/packages/exec
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

20
.licenses/npm/@actions/github.dep.yml generated Normal file
View File

@ -0,0 +1,20 @@
---
name: "@actions/github"
version: 6.0.0
type: npm
summary: Actions github lib
homepage: https://github.com/actions/toolkit/tree/main/packages/github
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@ -0,0 +1,32 @@
---
name: "@actions/http-client"
version: 2.2.1
type: npm
summary: Actions Http Client
homepage: https://github.com/actions/toolkit/tree/main/packages/http-client
license: mit
licenses:
- sources: LICENSE
text: |
Actions Http Client for Node.js
Copyright (c) GitHub, Inc.
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

20
.licenses/npm/@actions/io.dep.yml generated Normal file
View File

@ -0,0 +1,20 @@
---
name: "@actions/io"
version: 1.1.3
type: npm
summary: Actions io lib
homepage: https://github.com/actions/toolkit/tree/main/packages/io
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@actions/tool-cache"
version: 2.0.1
type: npm
summary: Actions tool-cache lib
homepage: https://github.com/actions/toolkit/tree/main/packages/tool-cache
license: mit
licenses:
- sources: LICENSE.md
text: |-
The MIT License (MIT)
Copyright 2019 GitHub
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

30
.licenses/npm/@fastify/busboy.dep.yml generated Normal file
View File

@ -0,0 +1,30 @@
---
name: "@fastify/busboy"
version: 2.1.1
type: npm
summary: A streaming parser for HTML form data for node.js
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright Brian White. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
notices: []

View File

@ -0,0 +1,34 @@
---
name: "@octokit/auth-token"
version: 4.0.0
type: npm
summary: GitHub API token authentication for browsers and Node.js
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

34
.licenses/npm/@octokit/core.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/core"
version: 5.2.0
type: npm
summary: Extendable client for GitHub's REST & GraphQL APIs
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

34
.licenses/npm/@octokit/endpoint.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/endpoint"
version: 9.0.5
type: npm
summary: Turns REST API endpoints into generic request options
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

34
.licenses/npm/@octokit/graphql.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: "@octokit/graphql"
version: 7.1.0
type: npm
summary: GitHub GraphQL API client for browsers and Node
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/openapi-types"
version: 20.0.0
type: npm
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright 2020 Gregor Martynus
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/openapi-types"
version: 22.1.0
type: npm
summary: Generated TypeScript definitions based on GitHub's OpenAPI spec for api.github.com
homepage:
license: mit
licenses:
- sources: LICENSE
text: |-
Copyright 2020 Gregor Martynus
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/plugin-paginate-rest"
version: 9.2.1
type: npm
summary: Octokit plugin to paginate REST API endpoint responses
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/plugin-rest-endpoint-methods"
version: 10.4.1
type: npm
summary: Octokit plugin adding one method for all of api.github.com REST API endpoints
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,34 @@
---
name: "@octokit/request-error"
version: 5.1.0
type: npm
summary: Error class for Octokit request errors
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

35
.licenses/npm/@octokit/request.dep.yml generated Normal file
View File

@ -0,0 +1,35 @@
---
name: "@octokit/request"
version: 8.4.0
type: npm
summary: Send parameterized requests to GitHub's APIs with sensible defaults in browsers
and Node
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License
Copyright (c) 2018 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/types"
version: 12.6.0
type: npm
summary: Shared TypeScript definitions for Octokit projects
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

View File

@ -0,0 +1,20 @@
---
name: "@octokit/types"
version: 13.4.1
type: npm
summary: Shared TypeScript definitions for Octokit projects
homepage:
license: mit
licenses:
- sources: LICENSE
text: |
MIT License Copyright (c) 2019 Octokit contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- sources: README.md
text: "[MIT](LICENSE)"
notices: []

214
.licenses/npm/before-after-hook.dep.yml generated Normal file
View File

@ -0,0 +1,214 @@
---
name: before-after-hook
version: 2.2.3
type: npm
summary: asynchronous before/error/after hooks for internal functionality
homepage:
license: apache-2.0
licenses:
- sources: LICENSE
text: |2
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Gregor Martynus and other contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
- sources: README.md
text: "[Apache 2.0](LICENSE)"
notices: []

28
.licenses/npm/deprecation.dep.yml generated Normal file
View File

@ -0,0 +1,28 @@
---
name: deprecation
version: 2.3.1
type: npm
summary: Log a deprecation message with stack
homepage: https://github.com/gr2m/deprecation#readme
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Gregor Martynus and contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- sources: README.md
text: "[ISC](LICENSE)"
notices: []

26
.licenses/npm/once.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: once
version: 1.4.0
type: npm
summary: Run a function exactly one time
homepage: https://github.com/isaacs/once#readme
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

26
.licenses/npm/semver.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: semver
version: 6.3.1
type: npm
summary: The semantic version parser used by npm.
homepage:
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

35
.licenses/npm/tunnel.dep.yml generated Normal file
View File

@ -0,0 +1,35 @@
---
name: tunnel
version: 0.0.6
type: npm
summary: Node HTTP/HTTPS Agents for tunneling proxies
homepage: https://github.com/koichik/node-tunnel/
license: mit
licenses:
- sources: LICENSE
text: |
The MIT License (MIT)
Copyright (c) 2012 Koichi Kobayashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
- sources: README.md
text: Licensed under the [MIT](https://github.com/koichik/node-tunnel/blob/master/LICENSE)
license.
notices: []

34
.licenses/npm/undici.dep.yml generated Normal file
View File

@ -0,0 +1,34 @@
---
name: undici
version: 5.28.4
type: npm
summary: An HTTP/1.1 client, written from scratch for Node.js
homepage: https://undici.nodejs.org
license: mit
licenses:
- sources: LICENSE
text: |
MIT License
Copyright (c) Matteo Collina and Undici contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- sources: README.md
text: MIT
notices: []

View File

@ -0,0 +1,20 @@
---
name: universal-user-agent
version: 6.0.1
type: npm
summary: Get a user agent string in both browser and node
homepage:
license: isc
licenses:
- sources: LICENSE.md
text: |
# [ISC License](https://spdx.org/licenses/ISC)
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- sources: README.md
text: "[ISC](LICENSE.md)"
notices: []

39
.licenses/npm/uuid-3.4.0.dep.yml generated Normal file
View File

@ -0,0 +1,39 @@
---
name: uuid
version: 3.4.0
type: npm
summary: RFC4122 (v1, v4, and v5) UUIDs
homepage:
license: mit
licenses:
- sources: LICENSE.md
text: |
The MIT License (MIT)
Copyright (c) 2010-2016 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
notices:
- sources: AUTHORS
text: |-
Robert Kieffer <robert@broofa.com>
Christoph Tavan <dev@tavan.de>
AJ ONeal <coolaj86@gmail.com>
Vincent Voyer <vincent@zeroload.net>
Roman Shtylman <shtylman@gmail.com>

20
.licenses/npm/uuid-8.3.2.dep.yml generated Normal file
View File

@ -0,0 +1,20 @@
---
name: uuid
version: 8.3.2
type: npm
summary: RFC4122 (v1, v4, and v5) UUIDs
homepage: https://github.com/uuidjs/uuid#readme
license: mit
licenses:
- sources: LICENSE.md
text: |
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

20
.licenses/npm/uuid-9.0.1.dep.yml generated Normal file
View File

@ -0,0 +1,20 @@
---
name: uuid
version: 9.0.1
type: npm
summary: RFC4122 (v1, v4, and v5) UUIDs
homepage:
license: mit
licenses:
- sources: LICENSE.md
text: |
The MIT License (MIT)
Copyright (c) 2010-2020 Robert Kieffer and other contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
notices: []

26
.licenses/npm/wrappy.dep.yml generated Normal file
View File

@ -0,0 +1,26 @@
---
name: wrappy
version: 1.0.2
type: npm
summary: Callback wrapping utility
homepage: https://github.com/npm/wrappy
license: isc
licenses:
- sources: LICENSE
text: |
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
notices: []

View File

@ -1,47 +1,160 @@
# Changelog
# 更新日志
## v4.2.2
* `url-helper.ts` 现在利用众所周知的环境变量,由 @jww3 在 https://github.com/actions/checkout/pull/1941 中贡献
* 扩展 `isGhes` 的单元测试覆盖率,由 @jww3 在 https://github.com/actions/checkout/pull/1946 中贡献
## v4.2.1
* 如果提供了 commit,则检出其他 refs/*,否则回退到 ref,由 @orhantoy 在 https://github.com/actions/checkout/pull/1924 中贡献
## v4.2.0
* 添加 Ref 和 Commit 输出,由 @lucacome 在 https://github.com/actions/checkout/pull/1180 中贡献
* 依赖项更新,由 @dependabot 在 https://github.com/actions/checkout/pull/1777 和 https://github.com/actions/checkout/pull/1872 中贡献
## v4.1.7
* 在 1 个目录中更新次要 npm 依赖项组,共 4 次更新,由 @dependabot 在 https://github.com/actions/checkout/pull/1739 中贡献
* 将 actions/checkout 从 3 升级到 4,由 @dependabot 在 https://github.com/actions/checkout/pull/1697 中贡献
* 按 commit 检出其他 refs/*,由 @orhantoy 在 https://github.com/actions/checkout/pull/1774 中贡献
* 将 actions/checkout 自身的工作流固定到已知、良好、稳定的版本,由 @jww3 在 https://github.com/actions/checkout/pull/1776 中贡献
## v4.1.6
* 检查平台以适当设置存档扩展名,由 @cory-miller 在 https://github.com/actions/checkout/pull/1732 中贡献
## v4.1.5
* 更新 NPM 依赖项,由 @cory-miller 在 https://github.com/actions/checkout/pull/1703 中贡献
* 将 github/codeql-action 从 2 升级到 3,由 @dependabot 在 https://github.com/actions/checkout/pull/1694 中贡献
* 将 actions/setup-node 从 1 升级到 4,由 @dependabot 在 https://github.com/actions/checkout/pull/1696 中贡献
* 将 actions/upload-artifact 从 2 升级到 4,由 @dependabot 在 https://github.com/actions/checkout/pull/1695 中贡献
* README:建议将 `user.email` 设置为 `41898282+github-actions[bot]@users.noreply.github.com`,由 @cory-miller 在 https://github.com/actions/checkout/pull/1707 中贡献
## v4.1.4
- 禁用 `sparse-checkout` 时禁用 `extensions.worktreeConfig`,由 @jww3 在 https://github.com/actions/checkout/pull/1692 中贡献
- 添加 dependabot 配置,由 @cory-miller 在 https://github.com/actions/checkout/pull/1688 中贡献
- 使用 2 次更新更新次要 actions 依赖项组,由 @dependabot 在 https://github.com/actions/checkout/pull/1693 中贡献
- 将 word-wrap 从 1.2.3 升级到 1.2.5,由 @dependabot 在 https://github.com/actions/checkout/pull/1643 中贡献
## v4.1.3
- 在尝试禁用 `sparse-checkout` 之前检查 git 版本,由 @jww3 在 https://github.com/actions/checkout/pull/1656 中贡献
- 添加 SSH 用户参数,由 @cory-miller 在 https://github.com/actions/checkout/pull/1685 中贡献
-`update-main-version.yml` 中更新 `actions/checkout` 版本,由 @jww3 在 https://github.com/actions/checkout/pull/1650 中贡献
## v4.1.2
- 修复:当 `sparse-checkout` 选项不存在时禁用稀疏检出,由 @dscho 在 https://github.com/actions/checkout/pull/1598 中贡献
## v4.1.1
- 修正指向 GitHub 文档的链接,由 @peterbe 在 https://github.com/actions/checkout/pull/1511 中贡献
- 从“新特性”部分链接到发布页面,由 @cory-miller 在 https://github.com/actions/checkout/pull/1514 中贡献
## v4.1.0
- [添加对部分检出过滤器的支持](https://github.com/actions/checkout/pull/1396)
## v4.0.0
- [支持不带 --progress 选项的获取](https://github.com/actions/checkout/pull/1067)
- [升级到 node20](https://github.com/actions/checkout/pull/1436)
## v3.6.0
- [修复:将测试脚本标记为通过 Bash 运行的 Bash'isms](https://github.com/actions/checkout/pull/1377)
- [添加选项以在 fetch-depth > 0 时获取标签](https://github.com/actions/checkout/pull/579)
## v3.5.3
- [修复:在自托管运行器上检出失败,当有故障的子模块被签入时](https://github.com/actions/checkout/pull/1196)
- [修复 codespell 发现的拼写错误](https://github.com/actions/checkout/pull/1287)
- [添加对稀疏检出的支持](https://github.com/actions/checkout/pull/1369)
## v3.5.2
- [修复 GHES 的 api 端点](https://github.com/actions/checkout/pull/1289)
## v3.5.1
- [修复 Windows 上的慢速检出](https://github.com/actions/checkout/pull/1246)
## v3.5.0
* [添加新的 known_hosts 公钥](https://github.com/actions/checkout/pull/1237)
## v3.4.0
- [将 codeql actions 升级到 v2](https://github.com/actions/checkout/pull/1209)
- [升级依赖项](https://github.com/actions/checkout/pull/1210)
- [升级 @actions/io](https://github.com/actions/checkout/pull/1225)
## v3.3.0
- [通过 exec 函数的回调实现分支列表](https://github.com/actions/checkout/pull/1045)
- [明确引用私有检出选项](https://github.com/actions/checkout/pull/1050)
- [修复评论中的拼写错误(在 #770 中添加)](https://github.com/actions/checkout/pull/1057)
## v3.2.0
- [添加 GitHub Action 以执行发布](https://github.com/actions/checkout/pull/942)
- [修复状态徽章](https://github.com/actions/checkout/pull/967)
- [将 datadog/squid 替换为 ubuntu/squid Docker 镜像](https://github.com/actions/checkout/pull/1002)
- [在 submoduleForeach 的管道命令周围添加引号](https://github.com/actions/checkout/pull/964)
- [将 @actions/io 升级到 1.1.2](https://github.com/actions/checkout/pull/1029)
- [升级到版本 3.2.0](https://github.com/actions/checkout/pull/1039)
## v3.1.0
- [使用 @actions/core `saveState` 和 `getState`](https://github.com/actions/checkout/pull/939)
- [添加 `github-server-url` 输入](https://github.com/actions/checkout/pull/922)
## v3.0.2
- [添加输入 `set-safe-directory`](https://github.com/actions/checkout/pull/770)
## v3.0.1
- [修复了一个问题,由于新的 git 设置 `safe.directory`,导致在容器作业中无法运行 checkout](https://github.com/actions/checkout/pull/762)
- [提升各种 npm 包版本](https://github.com/actions/checkout/pull/744)
## v3.0.0
- [升级到 node 16](https://github.com/actions/checkout/pull/689)
## v2.3.1
- [修复 .wiki 的默认分支解析以及使用 SSH 时的解析](https://github.com/actions/checkout/pull/284)
## v2.3.0
- [回退到默认分支](https://github.com/actions/checkout/pull/278)
## v2.2.0
- [Fetch all history for all tags and branches when fetch-depth=0](https://github.com/actions/checkout/pull/258)
- [当 fetch-depth=0 时获取所有标签和分支的所有历史记录](https://github.com/actions/checkout/pull/258)
## v2.1.1
- Changes to support GHES ([here](https://github.com/actions/checkout/pull/236) and [here](https://github.com/actions/checkout/pull/248))
- 支持 GHES 的更改([这里](https://github.com/actions/checkout/pull/236) 和 [这里](https://github.com/actions/checkout/pull/248))
## v2.1.0
- [Group output](https://github.com/actions/checkout/pull/191)
- [Changes to support GHES alpha release](https://github.com/actions/checkout/pull/199)
- [Persist core.sshCommand for submodules](https://github.com/actions/checkout/pull/184)
- [Add support ssh](https://github.com/actions/checkout/pull/163)
- [Convert submodule SSH URL to HTTPS, when not using SSH](https://github.com/actions/checkout/pull/179)
- [Add submodule support](https://github.com/actions/checkout/pull/157)
- [Follow proxy settings](https://github.com/actions/checkout/pull/144)
- [Fix ref for pr closed event when a pr is merged](https://github.com/actions/checkout/pull/141)
- [Fix issue checking detached when git less than 2.22](https://github.com/actions/checkout/pull/128)
- [分组输出](https://github.com/actions/checkout/pull/191)
- [支持 GHES alpha 发布的更改](https://github.com/actions/checkout/pull/199)
- [为子模块持久化 core.sshCommand](https://github.com/actions/checkout/pull/184)
- [添加对 ssh 的支持](https://github.com/actions/checkout/pull/163)
- [当不使用 SSH 时,将子模块 SSH URL 转换为 HTTPS](https://github.com/actions/checkout/pull/179)
- [添加子模块支持](https://github.com/actions/checkout/pull/157)
- [遵循代理设置](https://github.com/actions/checkout/pull/144)
- [修复 pr 关闭事件的 ref,当 pr 被合并时](https://github.com/actions/checkout/pull/141)
- [修复 git 版本低于 2.22 时检查分离状态的问题](https://github.com/actions/checkout/pull/128)
## v2.0.0
- [Do not pass cred on command line](https://github.com/actions/checkout/pull/108)
- [Add input persist-credentials](https://github.com/actions/checkout/pull/107)
- [Fallback to REST API to download repo](https://github.com/actions/checkout/pull/104)
- [不在命令行上传递凭据](https://github.com/actions/checkout/pull/108)
- [添加输入 persist-credentials](https://github.com/actions/checkout/pull/107)
- [回退到 REST API 下载仓库](https://github.com/actions/checkout/pull/104)
## v2 (beta)
- Improved fetch performance
- The default behavior now fetches only the SHA being checked-out
- Script authenticated git commands
- Persists `with.token` in the local git config
- Enables your scripts to run authenticated git commands
- Post-job cleanup removes the token
- Coming soon: Opt out by setting `with.persist-credentials` to `false`
- Creates a local branch
- No longer detached HEAD when checking out a branch
- A local branch is created with the corresponding upstream branch set
- Improved layout
- `with.path` is always relative to `github.workspace`
- Aligns better with container actions, where `github.workspace` gets mapped in
- Removed input `submodules`
- 改进的获取性能
- 默认行为现在仅获取正在检出的 SHA
- 脚本认证的 git 命令
- `with.token` 持久化到本地 git 配置
- 使您的脚本可以运行经过身份验证的 git 命令
- 作业后清理移除令牌
- 即将推出:通过将 `with.persist-credentials` 设置为 `false` 来选择退出
- 创建本地分支
- 检出分支时不再是分离的 HEAD
- 创建一个带有相应上游分支设置的本地分支
- 改进的布局
- `with.path` 始终相对于 `github.workspace`
- 更好地与容器操作对齐,其中 `github.workspace` 被映射进来
- 移除输入 `submodules`
## v1
Refer [here](https://github.com/actions/checkout/blob/v1/CHANGELOG.md) for the V1 changelog
有关 V1 更新日志,请参阅 [这里](https://github.com/actions/checkout/blob/v1/CHANGELOG.md)

1
CODEOWNERS Normal file
View File

@ -0,0 +1 @@
* @actions/actions-launch

28
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,28 @@
# 贡献指南
## 提交拉取请求
1. Fork 并克隆仓库
1. 配置并安装依赖项:`npm install`
1. 创建新分支:`git checkout -b my-branch-name`
1. 进行更改,添加测试,并确保测试仍然通过:`npm run test`
1. 确保代码格式正确:`npm run format`
1. 使用 `npm run build` 更新 `dist/index.js`。这将创建一个作为操作入口点的单一 JavaScript 文件
1. 推送到您的 Fork 并提交拉取请求
1. 拍拍自己的背,等待您的拉取请求被审查和合并
以下是一些可以提高您的拉取请求被接受可能性的建议:
- 编写测试。
- 尽量保持更改的专注性。如果您希望进行多个不相互依赖的更改,建议将它们作为单独的拉取请求提交。
## 资源
- [如何为开源做贡献](https://opensource.guide/how-to-contribute/)
- [使用拉取请求](https://help.github.com/articles/about-pull-requests/)
- [GitHub 帮助](https://help.github.com)
- [编写良好的提交信息](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
谢谢!:heart: :heart: :heart:
GitHub Actions 团队 :octocat:

326
README.md
View File

@ -1,218 +1,330 @@
<p align="center">
<a href="https://github.com/actions/checkout"><img alt="GitHub Actions status" src="https://github.com/actions/checkout/workflows/test-local/badge.svg"></a>
</p>
[![构建和测试](https://github.com/actions/checkout/actions/workflows/test.yml/badge.svg)](https://github.com/actions/checkout/actions/workflows/test.yml)
# Checkout V2
# Checkout V4
This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it.
此操作将您的仓库检出到 `$GITHUB_WORKSPACE` 下,以便您的工作流可以访问它。
Only a single commit is fetched by default, for the ref/SHA that triggered the workflow. Set `fetch-depth: 0` to fetch all history for all branches and tags. Refer [here](https://help.github.com/en/articles/events-that-trigger-workflows) to learn which commit `$GITHUB_SHA` points to for different events.
默认情况下,仅获取触发工作流的 ref/SHA 的单个提交。设置 `fetch-depth: 0` 可以获取所有分支和标签的所有历史记录。请参考 [这里](https://docs.github.com/actions/using-workflows/events-that-trigger-workflows) 了解不同事件中 `$GITHUB_SHA` 指向的提交。
The auth token is persisted in the local git config. This enables your scripts to run authenticated git commands. The token is removed during post-job cleanup. Set `persist-credentials: false` to opt-out.
认证令牌会持久化到本地 git 配置中。这使得您的脚本可以运行经过身份验证的 git 命令。该令牌会在作业后清理步骤中被移除。设置 `persist-credentials: false` 可以选择不保留。
When Git 2.18 or higher is not in your PATH, falls back to the REST API to download the files.
Git 2.18 或更高版本不在您的 PATH 中时,将回退到 REST API 来下载文件。
# What's new
# 新特性
- Improved performance
- Fetches only a single commit by default
- Script authenticated git commands
- Auth token persisted in the local git config
- Supports SSH
- Creates a local branch
- No longer detached HEAD when checking out a branch
- Improved layout
- The input `path` is always relative to $GITHUB_WORKSPACE
- Aligns better with container actions, where $GITHUB_WORKSPACE gets mapped in
- Fallback to REST API download
- When Git 2.18 or higher is not in the PATH, the REST API will be used to download the files
- When using a job container, the container's PATH is used
请参考 [发布页面](https://github.com/actions/checkout/releases/latest) 获取最新的发布说明。
Refer [here](https://github.com/actions/checkout/blob/v1/README.md) for previous versions.
# Usage
# 使用方法
<!-- start usage -->
```yaml
- uses: actions/checkout@v2
uses: actions/checkout@v4
with:
# Repository name with owner. For example, actions/checkout
# Default: ${{ github.repository }}
# 仓库名称及所有者。例如,actions/checkout
# 默认值: ${{ github.repository }}
repository: ''
# The branch, tag or SHA to checkout. When checking out the repository that
# triggered a workflow, this defaults to the reference or SHA for that event.
# Otherwise, defaults to `master`.
# 要检出的分支、标签或 SHA。当检出触发工作流的仓库时,默认为该事件的引用或 SHA。
# 否则,使用默认分支。
ref: ''
# Personal access token (PAT) used to fetch the repository. The PAT is configured
# with the local git config, which enables your scripts to run authenticated git
# commands. The post-job step removes the PAT.
# 用于获取仓库的个人访问令牌 (PAT)。该 PAT 会配置到本地 git 配置中,使您的脚本可以运行经过身份验证的 git 命令。
# 作业后步骤会移除该 PAT。
#
# We recommend using a service account with the least permissions necessary. Also
# when generating a new PAT, select the least scopes necessary.
# 我们建议使用具有最低必要权限的服务账户。此外,在生成新的 PAT 时,请选择最低必要的范围。
#
# [Learn more about creating and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
# [了解有关创建和使用加密机密的更多信息](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
#
# Default: ${{ github.token }}
# 默认值: ${{ github.token }}
token: ''
# SSH key used to fetch the repository. The SSH key is configured with the local
# git config, which enables your scripts to run authenticated git commands. The
# post-job step removes the SSH key.
# 用于获取仓库的 SSH 密钥。该 SSH 密钥会配置到本地 git 配置中,使您的脚本可以运行经过身份验证的 git 命令。
# 作业后步骤会移除该 SSH 密钥。
#
# We recommend using a service account with the least permissions necessary.
# 我们建议使用具有最低必要权限的服务账户。
#
# [Learn more about creating and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
# [了解有关创建和使用加密机密的更多信息](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
ssh-key: ''
# Known hosts in addition to the user and global host key database. The public SSH
# keys for a host may be obtained using the utility `ssh-keyscan`. For example,
# `ssh-keyscan github.com`. The public key for github.com is always implicitly
# added.
# 除用户和全局主机密钥数据库之外的已知主机。可以使用 `ssh-keyscan` 工具获取主机的公共 SSH 密钥。例如,`ssh-keyscan github.com`。
# github.com 的公钥始终会隐式添加。
ssh-known-hosts: ''
# Whether to perform strict host key checking. When true, adds the options
# `StrictHostKeyChecking=yes` and `CheckHostIP=no` to the SSH command line. Use
# the input `ssh-known-hosts` to configure additional hosts.
# Default: true
# 是否执行严格的主机密钥检查。当为 true 时,会在 SSH 命令行中添加 `StrictHostKeyChecking=yes` 和 `CheckHostIP=no` 选项。
# 使用 `ssh-known-hosts` 输入来配置其他主机。
# 默认值: true
ssh-strict: ''
# Whether to configure the token or SSH key with the local git config
# Default: true
# 连接到远程 SSH 主机时使用的用户。默认值为 'git'。
# 默认值: git
ssh-user: ''
# 是否将令牌或 SSH 密钥配置到本地 git 配置中
# 默认值: true
persist-credentials: ''
# Relative path under $GITHUB_WORKSPACE to place the repository
# 在 $GITHUB_WORKSPACE 下放置仓库的相对路径
path: ''
# Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching
# Default: true
# 是否在获取前执行 `git clean -ffdx && git reset --hard HEAD`
# 默认值: true
clean: ''
# Number of commits to fetch. 0 indicates all history.
# Default: 1
# 针对给定过滤器进行部分克隆。如果设置了此选项,则会覆盖 sparse-checkout。
# 默认值: null
filter: ''
# 对给定模式进行稀疏检出。每个模式应以换行符分隔。
# 默认值: null
sparse-checkout: ''
# 指定在执行稀疏检出时是否使用 cone 模式。
# 默认值: true
sparse-checkout-cone-mode: ''
# 要获取的提交数量。0 表示所有分支和标签的所有历史记录。
# 默认值: 1
fetch-depth: ''
# Whether to download Git-LFS files
# Default: false
# 是否获取标签,即使 fetch-depth > 0。
# 默认值: false
fetch-tags: ''
# 获取时是否显示进度状态输出。
# 默认值: true
show-progress: ''
# 是否下载 Git-LFS 文件
# 默认值: false
lfs: ''
# Whether to checkout submodules: `true` to checkout submodules or `recursive` to
# recursively checkout submodules.
# 是否检出子模块:`true` 表示检出子模块,`recursive` 表示递归检出子模块。
#
# When the `ssh-key` input is not provided, SSH URLs beginning with
# `git@github.com:` are converted to HTTPS.
# 当未提供 `ssh-key` 输入时,以 `git@github.com:` 开头的 SSH URL 会被转换为 HTTPS。
#
# Default: false
# 默认值: false
submodules: ''
# 通过运行 `git config --global --add safe.directory <path>` 将仓库路径添加为 Git 全局配置的安全目录。
# 默认值: true
set-safe-directory: ''
# 尝试克隆的 GitHub 实例的基本 URL,将使用环境默认值从工作流运行的同一实例获取,除非指定。示例 URL 包括 https://github.com 或 https://my-ghes-server.example.com
github-server-url: ''
```
<!-- end usage -->
# Scenarios
# 场景
- [Fetch all history for all tags and branches](#Fetch-all-history-for-all-tags-and-branches)
- [Checkout a different branch](#Checkout-a-different-branch)
- [Checkout HEAD^](#Checkout-HEAD)
- [Checkout multiple repos (side by side)](#Checkout-multiple-repos-side-by-side)
- [Checkout multiple repos (nested)](#Checkout-multiple-repos-nested)
- [Checkout multiple repos (private)](#Checkout-multiple-repos-private)
- [Checkout pull request HEAD commit instead of merge commit](#Checkout-pull-request-HEAD-commit-instead-of-merge-commit)
- [Checkout pull request on closed event](#Checkout-pull-request-on-closed-event)
- [仅获取根文件](#Fetch-only-the-root-files)
- [仅获取根文件和 `.github` 及 `src` 文件夹](#Fetch-only-the-root-files-and-github-and-src-folder)
- [仅获取单个文件](#Fetch-only-a-single-file)
- [获取所有标签和分支的所有历史记录](#Fetch-all-history-for-all-tags-and-branches)
- [检出不同分支](#Checkout-a-different-branch)
- [检出 HEAD^](#Checkout-HEAD)
- [并行检出多个仓库](#Checkout-multiple-repos-side-by-side)
- [嵌套检出多个仓库](#Checkout-multiple-repos-nested)
- [检出多个私有仓库](#Checkout-multiple-repos-private)
- [检出拉取请求的 HEAD 提交而不是合并提交](#Checkout-pull-request-HEAD-commit-instead-of-merge-commit)
- [在关闭事件上检出拉取请求](#Checkout-pull-request-on-closed-event)
- [使用内置令牌推送提交](#Push-a-commit-using-the-built-in-token)
- [使用内置令牌向拉取请求推送提交](#Push-a-commit-to-a-PR-using-the-built-in-token)
## Fetch all history for all tags and branches
## 仅获取根文件
```yaml
- uses: actions/checkout@v2
uses: actions/checkout@v4
with:
sparse-checkout: .
```
## 仅获取根文件和 `.github` 及 `src` 文件夹
```yaml
• uses: actions/checkout@v4
with:
sparse-checkout: |
.github
src
```
## 仅获取单个文件
```yaml
• uses: actions/checkout@v4
with:
sparse-checkout: |
README.md
sparse-checkout-cone-mode: false
```
## 获取所有标签和分支的所有历史记录
```yaml
• uses: actions/checkout@v4
with:
fetch-depth: 0
```
## Checkout a different branch
## 检出不同分支
```yaml
- uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: my-branch
```
## Checkout HEAD^
## 检出 HEAD^
```yaml
- uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 2
- run: git checkout HEAD^
run: git checkout HEAD^
```
## Checkout multiple repos (side by side)
## 并行检出多个仓库
```yaml
- name: Checkout
uses: actions/checkout@v2
name: Checkout
uses: actions/checkout@v4
with:
path: main
- name: Checkout tools repo
uses: actions/checkout@v2
name: Checkout tools repo
uses: actions/checkout@v4
with:
repository: my-org/my-tools
path: my-tools
```
> - 如果您的次要仓库是私有或内部的,您需要添加 [Checkout multiple repos (private)](#Checkout-multiple-repos-private) 中提到的选项
## Checkout multiple repos (nested)
## 嵌套检出多个仓库
```yaml
- name: Checkout
uses: actions/checkout@v2
name: Checkout
- name: Checkout tools repo
uses: actions/checkout@v2
uses: actions/checkout@v4
• name: Checkout tools repo
uses: actions/checkout@v4
with:
repository: my-org/my-tools
path: my-tools
```
> - 如果您的次要仓库是私有或内部的,您需要添加 [Checkout multiple repos (private)](#Checkout-multiple-repos-private) 中提到的选项
## Checkout multiple repos (private)
## 检出多个私有仓库
```yaml
- name: Checkout
uses: actions/checkout@v2
name: Checkout
uses: actions/checkout@v4
with:
path: main
- name: Checkout private tools
uses: actions/checkout@v2
name: Checkout private tools
uses: actions/checkout@v4
with:
repository: my-org/my-private-tools
token: ${{ secrets.GitHub_PAT }} # `GitHub_PAT` is a secret that contains your PAT
token: ${{ secrets.GH_PAT }} # `GH_PAT` 是包含您 PAT 的机密
path: my-tools
```
> - `${{ github.token }}` 的范围限定在当前仓库,因此如果您想检出其他私有仓库,则需要提供您自己的 [PAT](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)。
> - `${{ github.token }}` is scoped to the current repository, so if you want to checkout a different repository that is private you will need to provide your own [PAT](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line).
## Checkout pull request HEAD commit instead of merge commit
## 检出拉取请求的 HEAD 提交而不是合并提交
```yaml
- uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
```
## Checkout pull request on closed event
## 在关闭事件上检出拉取请求
```yaml
on:
pull_request:
branches: [master]
branches: [main]
types: [opened, synchronize, closed]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
uses: actions/checkout@v4
```
# License
## 使用内置令牌推送提交
The scripts and documentation in this project are released under the [MIT License](LICENSE)
```yaml
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
◦ uses: actions/checkout@v4
◦ run: |
date > generated.txt
# 注意:以下账户信息在 GHES 上不起作用
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "generated"
git push
```
*注意:* 用户邮箱为 `{user.id}+{user.login}@users.noreply.github.com`。请参阅用户 API: https://api.github.com/users/github-actions%5Bbot%5D
## 使用内置令牌向拉取请求推送提交
在拉取请求触发器中,需要指定 `ref`,因为 GitHub Actions 默认以分离的 HEAD 模式检出,这意味着它不会默认检出您的分支。
```yaml
on: pull_request
jobs:
build:
runs-on: ubuntu-latest
steps:
◦ uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
◦ run: |
date > generated.txt
# 注意:以下账户信息在 GHES 上不起作用
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "generated"
git push
```
*注意:* 用户邮箱为 `{user.id}+{user.login}@users.noreply.github.com`。请参阅用户 API: https://api.github.com/users/github-actions%5Bbot%5D
# 推荐权限
在 GitHub Actions 工作流中使用 `checkout` 操作时,建议设置以下 `GITHUB_TOKEN` 权限以确保正常功能,除非通过 `token``ssh-key` 输入提供了替代身份验证:
```yaml
permissions:
contents: read
```
# 许可证
此项目中的脚本和文档均根据 [MIT 许可证](LICENSE) 发布

View File

@ -20,6 +20,7 @@ let tempHomedir: string
let git: IGitCommandManager & {env: {[key: string]: string}}
let settings: IGitSourceSettings
let sshPath: string
let githubServerUrl: string
describe('git-auth-helper tests', () => {
beforeAll(async () => {
@ -67,11 +68,18 @@ describe('git-auth-helper tests', () => {
}
})
const configureAuth_configuresAuthHeader =
'configureAuth configures auth header'
it(configureAuth_configuresAuthHeader, async () => {
async function testAuthHeader(
testName: string,
serverUrl: string | undefined = undefined
) {
// Arrange
await setup(configureAuth_configuresAuthHeader)
let expectedServerUrl = 'https://github.com'
if (serverUrl) {
githubServerUrl = serverUrl
expectedServerUrl = githubServerUrl
}
await setup(testName)
expect(settings.authToken).toBeTruthy() // sanity check
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
@ -88,9 +96,33 @@ describe('git-auth-helper tests', () => {
).toString('base64')
expect(
configContent.indexOf(
`http.https://github.com/.extraheader AUTHORIZATION: basic ${basicCredential}`
`http.${expectedServerUrl}/.extraheader AUTHORIZATION: basic ${basicCredential}`
)
).toBeGreaterThanOrEqual(0)
}
const configureAuth_configuresAuthHeader =
'configureAuth configures auth header'
it(configureAuth_configuresAuthHeader, async () => {
await testAuthHeader(configureAuth_configuresAuthHeader)
})
const configureAuth_AcceptsGitHubServerUrl =
'inject https://my-ghes-server.com as github server url'
it(configureAuth_AcceptsGitHubServerUrl, async () => {
await testAuthHeader(
configureAuth_AcceptsGitHubServerUrl,
'https://my-ghes-server.com'
)
})
const configureAuth_AcceptsGitHubServerUrlSetToGHEC =
'inject https://github.com as github server url'
it(configureAuth_AcceptsGitHubServerUrlSetToGHEC, async () => {
await testAuthHeader(
configureAuth_AcceptsGitHubServerUrl,
'https://github.com'
)
})
const configureAuth_configuresAuthHeaderEvenWhenPersistCredentialsFalse =
@ -137,8 +169,9 @@ describe('git-auth-helper tests', () => {
// Mock fs.promises.readFile
const realReadFile = fs.promises.readFile
jest.spyOn(fs.promises, 'readFile').mockImplementation(
async (file: any, options: any): Promise<Buffer> => {
jest
.spyOn(fs.promises, 'readFile')
.mockImplementation(async (file: any, options: any): Promise<Buffer> => {
const userKnownHostsPath = path.join(
os.homedir(),
'.ssh',
@ -149,8 +182,7 @@ describe('git-auth-helper tests', () => {
}
return await realReadFile(file, options)
}
)
})
// Act
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
@ -417,7 +449,7 @@ describe('git-auth-helper tests', () => {
`Did not expect file to exist: '${globalGitConfigPath}'`
)
} catch (err) {
if (err.code !== 'ENOENT') {
if ((err as any)?.code !== 'ENOENT') {
throw err
}
}
@ -518,12 +550,17 @@ describe('git-auth-helper tests', () => {
await authHelper.configureSubmoduleAuth()
// Assert
expect(mockSubmoduleForeach).toHaveBeenCalledTimes(3)
expect(mockSubmoduleForeach).toHaveBeenCalledTimes(4)
expect(mockSubmoduleForeach.mock.calls[0][0]).toMatch(
/unset-all.*insteadOf/
)
expect(mockSubmoduleForeach.mock.calls[1][0]).toMatch(/http.*extraheader/)
expect(mockSubmoduleForeach.mock.calls[2][0]).toMatch(/url.*insteadOf/)
expect(mockSubmoduleForeach.mock.calls[2][0]).toMatch(
/url.*insteadOf.*git@github.com:/
)
expect(mockSubmoduleForeach.mock.calls[3][0]).toMatch(
/url.*insteadOf.*org-123456@github.com:/
)
}
)
@ -601,7 +638,7 @@ describe('git-auth-helper tests', () => {
await fs.promises.stat(actualKeyPath)
throw new Error('SSH key should have been deleted')
} catch (err) {
if (err.code !== 'ENOENT') {
if ((err as any)?.code !== 'ENOENT') {
throw err
}
}
@ -611,7 +648,7 @@ describe('git-auth-helper tests', () => {
await fs.promises.stat(actualKnownHostsPath)
throw new Error('SSH known hosts should have been deleted')
} catch (err) {
if (err.code !== 'ENOENT') {
if ((err as any)?.code !== 'ENOENT') {
throw err
}
}
@ -638,10 +675,11 @@ describe('git-auth-helper tests', () => {
expect(gitConfigContent.indexOf('http.')).toBeLessThan(0)
})
const removeGlobalAuth_removesOverride = 'removeGlobalAuth removes override'
it(removeGlobalAuth_removesOverride, async () => {
const removeGlobalConfig_removesOverride =
'removeGlobalConfig removes override'
it(removeGlobalConfig_removesOverride, async () => {
// Arrange
await setup(removeGlobalAuth_removesOverride)
await setup(removeGlobalConfig_removesOverride)
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
await authHelper.configureAuth()
await authHelper.configureGlobalAuth()
@ -650,7 +688,7 @@ describe('git-auth-helper tests', () => {
await fs.promises.stat(path.join(git.env['HOME'], '.gitconfig'))
// Act
await authHelper.removeGlobalAuth()
await authHelper.removeGlobalConfig()
// Assert
expect(git.env['HOME']).toBeUndefined()
@ -658,7 +696,7 @@ describe('git-auth-helper tests', () => {
await fs.promises.stat(homeOverride)
throw new Error(`Should have been deleted '${homeOverride}'`)
} catch (err) {
if (err.code !== 'ENOENT') {
if ((err as any)?.code !== 'ENOENT') {
throw err
}
}
@ -689,6 +727,9 @@ async function setup(testName: string): Promise<void> {
branchDelete: jest.fn(),
branchExists: jest.fn(),
branchList: jest.fn(),
disableSparseCheckout: jest.fn(),
sparseCheckout: jest.fn(),
sparseCheckoutNonConeMode: jest.fn(),
checkout: jest.fn(),
checkoutDetach: jest.fn(),
config: jest.fn(
@ -714,6 +755,7 @@ async function setup(testName: string): Promise<void> {
),
env: {},
fetch: jest.fn(),
getDefaultBranch: jest.fn(),
getWorkingDirectory: jest.fn(() => workspace),
init: jest.fn(),
isDetached: jest.fn(),
@ -731,6 +773,9 @@ async function setup(testName: string): Promise<void> {
return ''
}),
submoduleSync: jest.fn(),
submoduleStatus: jest.fn(async () => {
return true
}),
submoduleUpdate: jest.fn(),
tagExists: jest.fn(),
tryClean: jest.fn(),
@ -751,25 +796,35 @@ async function setup(testName: string): Promise<void> {
),
tryDisableAutomaticGarbageCollection: jest.fn(),
tryGetFetchUrl: jest.fn(),
tryReset: jest.fn()
tryReset: jest.fn(),
version: jest.fn()
}
settings = {
authToken: 'some auth token',
clean: true,
commit: '',
filter: undefined,
sparseCheckout: [],
sparseCheckoutConeMode: true,
fetchDepth: 1,
fetchTags: false,
showProgress: true,
lfs: false,
submodules: false,
nestedSubmodules: false,
persistCredentials: true,
ref: 'refs/heads/master',
ref: 'refs/heads/main',
repositoryName: 'my-repo',
repositoryOwner: 'my-org',
repositoryPath: '',
sshKey: sshPath ? 'some ssh private key' : '',
sshKnownHosts: '',
sshStrict: true
sshStrict: true,
sshUser: '',
workflowOrganizationId: 123456,
setSafeDirectory: true,
githubServerUrl: githubServerUrl
}
}

View File

@ -0,0 +1,378 @@
import * as exec from '@actions/exec'
import * as fshelper from '../lib/fs-helper'
import * as commandManager from '../lib/git-command-manager'
let git: commandManager.IGitCommandManager
let mockExec = jest.fn()
describe('git-auth-helper tests', () => {
beforeAll(async () => {})
beforeEach(async () => {
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
})
afterEach(() => {
jest.restoreAllMocks()
})
afterAll(() => {})
it('branch list matches', async () => {
mockExec.mockImplementation((path, args, options) => {
console.log(args, options.listeners.stdout)
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
return 0
}
if (args.includes('rev-parse')) {
options.listeners.stdline(Buffer.from('refs/heads/foo'))
options.listeners.stdline(Buffer.from('refs/heads/bar'))
return 0
}
return 1
})
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
let branches = await git.branchList(false)
expect(branches).toHaveLength(2)
expect(branches.sort()).toEqual(['foo', 'bar'].sort())
})
it('ambiguous ref name output is captured', async () => {
mockExec.mockImplementation((path, args, options) => {
console.log(args, options.listeners.stdout)
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
return 0
}
if (args.includes('rev-parse')) {
options.listeners.stdline(Buffer.from('refs/heads/foo'))
// If refs/tags/v1 and refs/heads/tags/v1 existed on this repository
options.listeners.errline(
Buffer.from("error: refname 'tags/v1' is ambiguous")
)
return 0
}
return 1
})
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
let branches = await git.branchList(false)
expect(branches).toHaveLength(1)
expect(branches.sort()).toEqual(['foo'].sort())
})
})
describe('Test fetchDepth and fetchTags options', () => {
beforeEach(async () => {
jest.spyOn(fshelper, 'fileExistsSync').mockImplementation(jest.fn())
jest.spyOn(fshelper, 'directoryExistsSync').mockImplementation(jest.fn())
mockExec.mockImplementation((path, args, options) => {
console.log(args, options.listeners.stdout)
if (args.includes('version')) {
options.listeners.stdout(Buffer.from('2.18'))
}
return 0
})
})
afterEach(() => {
jest.restoreAllMocks()
})
it('should call execGit with the correct arguments when fetchDepth is 0 and fetchTags is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 0,
fetchTags: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 0 and fetchTags is false', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 0,
fetchTags: false
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 1 and fetchTags is false', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 1,
fetchTags: false
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'--depth=1',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 1 and fetchTags is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 1,
fetchTags: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--prune',
'--no-recurse-submodules',
'--filter=filterValue',
'--depth=1',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when showProgress is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
showProgress: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--progress',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchDepth is 42 and showProgress is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchDepth: 42,
showProgress: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--no-tags',
'--prune',
'--no-recurse-submodules',
'--progress',
'--filter=filterValue',
'--depth=42',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
it('should call execGit with the correct arguments when fetchTags is true and showProgress is true', async () => {
jest.spyOn(exec, 'exec').mockImplementation(mockExec)
const workingDirectory = 'test'
const lfs = false
const doSparseCheckout = false
git = await commandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
const refSpec = ['refspec1', 'refspec2']
const options = {
filter: 'filterValue',
fetchTags: true,
showProgress: true
}
await git.fetch(refSpec, options)
expect(mockExec).toHaveBeenCalledWith(
expect.any(String),
[
'-c',
'protocol.version=2',
'fetch',
'--prune',
'--no-recurse-submodules',
'--progress',
'--filter=filterValue',
'origin',
'refspec1',
'refspec2'
],
expect.any(Object)
)
})
})

View File

@ -281,6 +281,65 @@ describe('git-directory-helper tests', () => {
expect(git.branchDelete).toHaveBeenCalledWith(false, 'local-branch-2')
})
const cleanWhenSubmoduleStatusIsFalse =
'cleans when submodule status is false'
it(cleanWhenSubmoduleStatusIsFalse, async () => {
// Arrange
await setup(cleanWhenSubmoduleStatusIsFalse)
await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
//mock bad submodule
const submoduleStatus = git.submoduleStatus as jest.Mock<any, any>
submoduleStatus.mockImplementation(async (remote: boolean) => {
return false
})
// Act
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
clean,
ref
)
// Assert
const files = await fs.promises.readdir(repositoryPath)
expect(files).toHaveLength(0)
expect(git.tryClean).toHaveBeenCalled()
})
const doesNotCleanWhenSubmoduleStatusIsTrue =
'does not clean when submodule status is true'
it(doesNotCleanWhenSubmoduleStatusIsTrue, async () => {
// Arrange
await setup(doesNotCleanWhenSubmoduleStatusIsTrue)
await fs.promises.writeFile(path.join(repositoryPath, 'my-file'), '')
const submoduleStatus = git.submoduleStatus as jest.Mock<any, any>
submoduleStatus.mockImplementation(async (remote: boolean) => {
return true
})
// Act
await gitDirectoryHelper.prepareExistingDirectory(
git,
repositoryPath,
repositoryUrl,
clean,
ref
)
// Assert
const files = await fs.promises.readdir(repositoryPath)
expect(files.sort()).toEqual(['.git', 'my-file'])
expect(git.tryClean).toHaveBeenCalled()
})
const removesLockFiles = 'removes lock files'
it(removesLockFiles, async () => {
// Arrange
@ -403,11 +462,15 @@ async function setup(testName: string): Promise<void> {
branchList: jest.fn(async () => {
return []
}),
disableSparseCheckout: jest.fn(),
sparseCheckout: jest.fn(),
sparseCheckoutNonConeMode: jest.fn(),
checkout: jest.fn(),
checkoutDetach: jest.fn(),
config: jest.fn(),
configExists: jest.fn(),
fetch: jest.fn(),
getDefaultBranch: jest.fn(),
getWorkingDirectory: jest.fn(() => repositoryPath),
init: jest.fn(),
isDetached: jest.fn(),
@ -422,6 +485,9 @@ async function setup(testName: string): Promise<void> {
submoduleForeach: jest.fn(),
submoduleSync: jest.fn(),
submoduleUpdate: jest.fn(),
submoduleStatus: jest.fn(async () => {
return true
}),
tagExists: jest.fn(),
tryClean: jest.fn(async () => {
return true
@ -435,6 +501,7 @@ async function setup(testName: string): Promise<void> {
}),
tryReset: jest.fn(async () => {
return true
})
}),
version: jest.fn()
}
}

View File

@ -1,4 +1,5 @@
import {GitVersion} from '../lib/git-version'
import {GitVersion} from '../src/git-version'
import {MinimumGitSparseCheckoutVersion} from '../src/git-command-manager'
describe('git-version tests', () => {
it('basics', async () => {
@ -42,4 +43,44 @@ describe('git-version tests', () => {
expect(version.checkMinimum(new GitVersion('5.1'))).toBeFalsy()
expect(version.checkMinimum(new GitVersion('5.1.2'))).toBeFalsy()
})
it('sparse checkout', async () => {
const minSparseVer = MinimumGitSparseCheckoutVersion
expect(new GitVersion('1.0').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('1.99').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.0').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.24').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.24.0').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.24.9').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.25').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.25.0').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.25.1').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.25.9').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.26').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.26.0').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.26.1').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.26.9').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.27').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.27.0').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.27.1').checkMinimum(minSparseVer)).toBeFalsy()
expect(new GitVersion('2.27.9').checkMinimum(minSparseVer)).toBeFalsy()
// /---------------------------------------
// ^^^ before / after vvv
// --------------------------/
expect(new GitVersion('2.28').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.28.0').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.28.1').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.28.9').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.29').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.29.0').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.29.1').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.29.9').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('2.99').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('3.0').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('3.99').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('4.0').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('4.99').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('5.0').checkMinimum(minSparseVer)).toBeTruthy()
expect(new GitVersion('5.99').checkMinimum(minSparseVer)).toBeTruthy()
})
})

View File

@ -1,9 +1,9 @@
import * as assert from 'assert'
import * as core from '@actions/core'
import * as fsHelper from '../lib/fs-helper'
import * as github from '@actions/github'
import * as inputHelper from '../lib/input-helper'
import * as path from 'path'
import * as workflowContextHelper from '../lib/workflow-context-helper'
import {IGitSourceSettings} from '../lib/git-source-settings'
const originalGitHubWorkspace = process.env['GITHUB_WORKSPACE']
@ -43,6 +43,11 @@ describe('input-helper tests', () => {
.spyOn(fsHelper, 'directoryExistsSync')
.mockImplementation((path: string) => path == gitHubWorkspace)
// Mock ./workflowContextHelper getOrganizationId()
jest
.spyOn(workflowContextHelper, 'getOrganizationId')
.mockImplementation(() => Promise.resolve(123456))
// GitHub workspace
process.env['GITHUB_WORKSPACE'] = gitHubWorkspace
})
@ -67,26 +72,32 @@ describe('input-helper tests', () => {
jest.restoreAllMocks()
})
it('sets defaults', () => {
const settings: IGitSourceSettings = inputHelper.getInputs()
it('sets defaults', async () => {
const settings: IGitSourceSettings = await inputHelper.getInputs()
expect(settings).toBeTruthy()
expect(settings.authToken).toBeFalsy()
expect(settings.clean).toBe(true)
expect(settings.commit).toBeTruthy()
expect(settings.commit).toBe('1234567890123456789012345678901234567890')
expect(settings.filter).toBe(undefined)
expect(settings.sparseCheckout).toBe(undefined)
expect(settings.sparseCheckoutConeMode).toBe(true)
expect(settings.fetchDepth).toBe(1)
expect(settings.fetchTags).toBe(false)
expect(settings.showProgress).toBe(true)
expect(settings.lfs).toBe(false)
expect(settings.ref).toBe('refs/heads/some-ref')
expect(settings.repositoryName).toBe('some-repo')
expect(settings.repositoryOwner).toBe('some-owner')
expect(settings.repositoryPath).toBe(gitHubWorkspace)
expect(settings.setSafeDirectory).toBe(true)
})
it('qualifies ref', () => {
it('qualifies ref', async () => {
let originalRef = github.context.ref
try {
github.context.ref = 'some-unqualified-ref'
const settings: IGitSourceSettings = inputHelper.getInputs()
const settings: IGitSourceSettings = await inputHelper.getInputs()
expect(settings).toBeTruthy()
expect(settings.commit).toBe('1234567890123456789012345678901234567890')
expect(settings.ref).toBe('refs/heads/some-unqualified-ref')
@ -95,39 +106,42 @@ describe('input-helper tests', () => {
}
})
it('requires qualified repo', () => {
it('requires qualified repo', async () => {
inputs.repository = 'some-unqualified-repo'
assert.throws(() => {
inputHelper.getInputs()
}, /Invalid repository 'some-unqualified-repo'/)
try {
await inputHelper.getInputs()
throw 'should not reach here'
} catch (err) {
expect(`(${(err as any).message}`).toMatch(
"Invalid repository 'some-unqualified-repo'"
)
}
})
it('roots path', () => {
it('roots path', async () => {
inputs.path = 'some-directory/some-subdirectory'
const settings: IGitSourceSettings = inputHelper.getInputs()
const settings: IGitSourceSettings = await inputHelper.getInputs()
expect(settings.repositoryPath).toBe(
path.join(gitHubWorkspace, 'some-directory', 'some-subdirectory')
)
})
it('sets correct default ref/sha for other repo', () => {
inputs.repository = 'some-owner/some-other-repo'
const settings: IGitSourceSettings = inputHelper.getInputs()
expect(settings.ref).toBe('refs/heads/master')
expect(settings.commit).toBeFalsy()
})
it('sets ref to empty when explicit sha', () => {
it('sets ref to empty when explicit sha', async () => {
inputs.ref = '1111111111222222222233333333334444444444'
const settings: IGitSourceSettings = inputHelper.getInputs()
const settings: IGitSourceSettings = await inputHelper.getInputs()
expect(settings.ref).toBeFalsy()
expect(settings.commit).toBe('1111111111222222222233333333334444444444')
})
it('sets sha to empty when explicit ref', () => {
it('sets sha to empty when explicit ref', async () => {
inputs.ref = 'refs/heads/some-other-ref'
const settings: IGitSourceSettings = inputHelper.getInputs()
const settings: IGitSourceSettings = await inputHelper.getInputs()
expect(settings.ref).toBe('refs/heads/some-other-ref')
expect(settings.commit).toBeFalsy()
})
it('sets workflow organization ID', async () => {
const settings: IGitSourceSettings = await inputHelper.getInputs()
expect(settings.workflowOrganizationId).toBe(123456)
})
})

View File

@ -2,5 +2,5 @@
mkdir override-git-version
cd override-git-version
echo @echo override git version 1.2.3 > git.cmd
echo ::add-path::%CD%
echo "%CD%" >> $GITHUB_PATH
cd ..

View File

@ -5,5 +5,5 @@ cd override-git-version
echo "#!/bin/sh" > git
echo "echo override git version 1.2.3" >> git
chmod +x git
echo "::add-path::$(pwd)"
echo "$(pwd)" >> $GITHUB_PATH
cd ..

View File

@ -7,16 +7,16 @@ let git: IGitCommandManager
describe('ref-helper tests', () => {
beforeEach(() => {
git = ({} as unknown) as IGitCommandManager
git = {} as unknown as IGitCommandManager
})
it('getCheckoutInfo requires git', async () => {
const git = (null as unknown) as IGitCommandManager
const git = null as unknown as IGitCommandManager
try {
await refHelper.getCheckoutInfo(git, 'refs/heads/my/branch', commit)
throw new Error('Should not reach here')
} catch (err) {
expect(err.message).toBe('Arg git cannot be empty')
expect((err as any)?.message).toBe('Arg git cannot be empty')
}
})
@ -25,7 +25,9 @@ describe('ref-helper tests', () => {
await refHelper.getCheckoutInfo(git, '', '')
throw new Error('Should not reach here')
} catch (err) {
expect(err.message).toBe('Args ref and commit cannot both be empty')
expect((err as any)?.message).toBe(
'Args ref and commit cannot both be empty'
)
}
})
@ -65,6 +67,26 @@ describe('ref-helper tests', () => {
expect(checkoutInfo.startPoint).toBeFalsy()
})
it('getCheckoutInfo refs/', async () => {
const checkoutInfo = await refHelper.getCheckoutInfo(
git,
'refs/gh/queue/main/pr-123',
commit
)
expect(checkoutInfo.ref).toBe(commit)
expect(checkoutInfo.startPoint).toBeFalsy()
})
it('getCheckoutInfo refs/ without commit', async () => {
const checkoutInfo = await refHelper.getCheckoutInfo(
git,
'refs/non-standard-ref',
''
)
expect(checkoutInfo.ref).toBe('refs/non-standard-ref')
expect(checkoutInfo.startPoint).toBeFalsy()
})
it('getCheckoutInfo unqualified branch only', async () => {
git.branchExists = jest.fn(async (remote: boolean, pattern: string) => {
return true
@ -102,7 +124,7 @@ describe('ref-helper tests', () => {
await refHelper.getCheckoutInfo(git, 'my-ref', '')
throw new Error('Should not reach here')
} catch (err) {
expect(err.message).toBe(
expect((err as any)?.message).toBe(
"A branch or tag with the name 'my-ref' could not be found"
)
}

View File

@ -68,13 +68,13 @@ describe('retry-helper tests', () => {
it('all attempts fail succeeds', async () => {
let attempts = 0
let error: Error = (null as unknown) as Error
let error: Error = null as unknown as Error
try {
await retryHelper.execute(() => {
throw new Error(`some error ${++attempts}`)
})
} catch (err) {
error = err
error = err as Error
}
expect(error.message).toBe('some error 3')
expect(attempts).toBe(3)

View File

@ -0,0 +1,92 @@
import * as urlHelper from '../src/url-helper'
describe('getServerUrl tests', () => {
it('basics', async () => {
// Note that URL::toString will append a trailing / when passed just a domain name ...
expect(urlHelper.getServerUrl().toString()).toBe('https://github.com/')
expect(urlHelper.getServerUrl(' ').toString()).toBe('https://github.com/')
expect(urlHelper.getServerUrl(' ').toString()).toBe('https://github.com/')
expect(urlHelper.getServerUrl('http://contoso.com').toString()).toBe(
'http://contoso.com/'
)
expect(urlHelper.getServerUrl('https://contoso.com').toString()).toBe(
'https://contoso.com/'
)
expect(urlHelper.getServerUrl('https://contoso.com/').toString()).toBe(
'https://contoso.com/'
)
// ... but can't make that same assumption when passed an URL that includes some deeper path.
expect(urlHelper.getServerUrl('https://contoso.com/a/b').toString()).toBe(
'https://contoso.com/a/b'
)
})
})
describe('isGhes tests', () => {
const pristineEnv = process.env
beforeEach(() => {
jest.resetModules()
process.env = {...pristineEnv}
})
afterAll(() => {
process.env = pristineEnv
})
it('basics', async () => {
delete process.env['GITHUB_SERVER_URL']
expect(urlHelper.isGhes()).toBeFalsy()
expect(urlHelper.isGhes('https://github.com')).toBeFalsy()
expect(urlHelper.isGhes('https://contoso.ghe.com')).toBeFalsy()
expect(urlHelper.isGhes('https://test.github.localhost')).toBeFalsy()
expect(urlHelper.isGhes('https://src.onpremise.fabrikam.com')).toBeTruthy()
})
it('returns false when the GITHUB_SERVER_URL environment variable is not defined', async () => {
delete process.env['GITHUB_SERVER_URL']
expect(urlHelper.isGhes()).toBeFalsy()
})
it('returns false when the GITHUB_SERVER_URL environment variable is set to github.com', async () => {
process.env['GITHUB_SERVER_URL'] = 'https://github.com'
expect(urlHelper.isGhes()).toBeFalsy()
})
it('returns false when the GITHUB_SERVER_URL environment variable is set to a GitHub Enterprise Cloud-style URL', async () => {
process.env['GITHUB_SERVER_URL'] = 'https://contoso.ghe.com'
expect(urlHelper.isGhes()).toBeFalsy()
})
it('returns false when the GITHUB_SERVER_URL environment variable has a .localhost suffix', async () => {
process.env['GITHUB_SERVER_URL'] = 'https://mock-github.localhost'
expect(urlHelper.isGhes()).toBeFalsy()
})
it('returns true when the GITHUB_SERVER_URL environment variable is set to some other URL', async () => {
process.env['GITHUB_SERVER_URL'] = 'https://src.onpremise.fabrikam.com'
expect(urlHelper.isGhes()).toBeTruthy()
})
})
describe('getServerApiUrl tests', () => {
it('basics', async () => {
expect(urlHelper.getServerApiUrl()).toBe('https://api.github.com')
expect(urlHelper.getServerApiUrl('https://github.com')).toBe(
'https://api.github.com'
)
expect(urlHelper.getServerApiUrl('https://GitHub.com')).toBe(
'https://api.github.com'
)
expect(urlHelper.getServerApiUrl('https://contoso.ghe.com')).toBe(
'https://api.contoso.ghe.com'
)
expect(urlHelper.getServerApiUrl('https://fabrikam.GHE.COM')).toBe(
'https://api.fabrikam.ghe.com'
)
expect(
urlHelper.getServerApiUrl('https://src.onpremise.fabrikam.com')
).toBe('https://src.onpremise.fabrikam.com/api/v3')
})
})

View File

@ -18,7 +18,21 @@ else
exit 1
fi
# Verify that sparse-checkout is disabled.
SPARSE_CHECKOUT_ENABLED=$(git -C ./basic config --local --get-all core.sparseCheckout)
if [ "$SPARSE_CHECKOUT_ENABLED" != "" ]; then
echo "Expected sparse-checkout to be disabled (discovered: $SPARSE_CHECKOUT_ENABLED)"
exit 1
fi
# Verify git configuration shows worktreeConfig is effectively disabled
WORKTREE_CONFIG_ENABLED=$(git -C ./basic config --local --get-all extensions.worktreeConfig)
if [[ "$WORKTREE_CONFIG_ENABLED" != "" ]]; then
echo "Expected extensions.worktreeConfig (boolean) to be disabled in git config. This could be an artifact of sparse checkout functionality."
exit 1
fi
# Verify auth token
cd basic
git fetch --no-tags --depth=1 origin +refs/heads/master:refs/remotes/origin/master
git fetch --no-tags --depth=1 origin +refs/heads/main:refs/remotes/origin/main
fi

16
__test__/verify-fetch-filter.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
# Verify .git folder
if [ ! -d "./fetch-filter/.git" ]; then
echo "Expected ./fetch-filter/.git folder to exist"
exit 1
fi
# Verify .git/config contains partialclonefilter
CLONE_FILTER=$(git -C fetch-filter config --local --get remote.origin.partialclonefilter)
if [ "$CLONE_FILTER" != "blob:none" ]; then
echo "Expected ./fetch-filter/.git/config to have 'remote.origin.partialclonefilter' set to 'blob:none'"
exit 1
fi

View File

@ -12,6 +12,6 @@ if [[ "$(git status --porcelain)" != "" ]]; then
echo ----------------------------------------
echo Troubleshooting
echo ----------------------------------------
echo "::error::Unstaged changes detected. Locally try running: git clean -ffdx && npm ci && npm run all"
echo "::error::Unstaged changes detected. Locally try running: git clean -ffdx && npm ci && npm run format && npm run build"
exit 1
fi

View File

@ -0,0 +1,51 @@
#!/bin/bash
# Verify .git folder
if [ ! -d "./sparse-checkout-non-cone-mode/.git" ]; then
echo "Expected ./sparse-checkout-non-cone-mode/.git folder to exist"
exit 1
fi
# Verify sparse-checkout (non-cone-mode)
cd sparse-checkout-non-cone-mode
ENABLED=$(git config --local --get-all core.sparseCheckout)
if [ "$?" != "0" ]; then
echo "Failed to verify that sparse-checkout is enabled"
exit 1
fi
# Check that sparse-checkout is enabled
if [ "$ENABLED" != "true" ]; then
echo "Expected sparse-checkout to be enabled (is: $ENABLED)"
exit 1
fi
SPARSE_CHECKOUT_FILE=$(git rev-parse --git-path info/sparse-checkout)
if [ "$?" != "0" ]; then
echo "Failed to validate sparse-checkout"
exit 1
fi
# Check that sparse-checkout list is not empty
if [ ! -f "$SPARSE_CHECKOUT_FILE" ]; then
echo "Expected sparse-checkout file to exist"
exit 1
fi
# Check that all folders from sparse-checkout exists
for pattern in $(cat "$SPARSE_CHECKOUT_FILE")
do
if [ ! -d "${pattern#/}" ]; then
echo "Expected directory '${pattern#/}' to exist"
exit 1
fi
done
# Verify that the root directory is not checked out
if [ -f README.md ]; then
echo "Expected top-level files not to exist"
exit 1
fi

View File

@ -0,0 +1,63 @@
#!/bin/bash
# Verify .git folder
if [ ! -d "./sparse-checkout/.git" ]; then
echo "Expected ./sparse-checkout/.git folder to exist"
exit 1
fi
# Verify sparse-checkout
cd sparse-checkout
SPARSE=$(git sparse-checkout list)
if [ "$?" != "0" ]; then
echo "Failed to validate sparse-checkout"
exit 1
fi
# Check that sparse-checkout list is not empty
if [ -z "$SPARSE" ]; then
echo "Expected sparse-checkout list to not be empty"
exit 1
fi
# Check that all folders of the sparse checkout exist
for pattern in $SPARSE
do
if [ ! -d "$pattern" ]; then
echo "Expected directory '$pattern' to exist"
exit 1
fi
done
checkSparse () {
if [ ! -d "./$1" ]; then
echo "Expected directory '$1' to exist"
exit 1
fi
for file in $(git ls-tree -r --name-only HEAD $1)
do
if [ ! -f "$file" ]; then
echo "Expected file '$file' to exist"
exit 1
fi
done
}
# Check that all folders and their children have been checked out
checkSparse __test__
checkSparse .github
checkSparse dist
# Check that only sparse-checkout folders have been checked out
for pattern in $(git ls-tree --name-only HEAD)
do
if [ -d "$pattern" ]; then
if [[ "$pattern" != "__test__" && "$pattern" != ".github" && "$pattern" != "dist" ]]; then
echo "Expected directory '$pattern' to not exist"
exit 1
fi
fi
done

View File

@ -8,7 +8,7 @@ inputs:
description: >
The branch, tag or SHA to checkout. When checking out the repository that
triggered a workflow, this defaults to the reference or SHA for that
event. Otherwise, defaults to `master`.
event. Otherwise, uses the default branch.
token:
description: >
Personal access token (PAT) used to fetch the repository. The PAT is configured
@ -45,6 +45,10 @@ inputs:
and `CheckHostIP=no` to the SSH command line. Use the input `ssh-known-hosts` to
configure additional hosts.
default: true
ssh-user:
description: >
The user to use when connecting to the remote SSH host. By default 'git' is used.
default: git
persist-credentials:
description: 'Whether to configure the token or SSH key with the local git config'
default: true
@ -53,9 +57,29 @@ inputs:
clean:
description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching'
default: true
filter:
description: >
Partially clone against a given filter.
Overrides sparse-checkout if set.
default: null
sparse-checkout:
description: >
Do a sparse checkout on given patterns.
Each pattern should be separated with new lines.
default: null
sparse-checkout-cone-mode:
description: >
Specifies whether to use cone-mode when doing a sparse checkout.
default: true
fetch-depth:
description: 'Number of commits to fetch. 0 indicates all history.'
description: 'Number of commits to fetch. 0 indicates all history for all branches and tags.'
default: 1
fetch-tags:
description: 'Whether to fetch tags, even if fetch-depth > 0.'
default: false
show-progress:
description: 'Whether to show progress status output when fetching.'
default: true
lfs:
description: 'Whether to download Git-LFS files'
default: false
@ -68,7 +92,18 @@ inputs:
When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are
converted to HTTPS.
default: false
set-safe-directory:
description: Add repository path as safe.directory for Git global config by running `git config --global --add safe.directory <path>`
default: true
github-server-url:
description: The base URL for the GitHub instance that you are trying to clone from, will use environment defaults to fetch from the same instance that the workflow is running from unless specified. Example URLs are https://github.com or https://my-ghes-server.example.com
required: false
outputs:
ref:
description: 'The branch, tag or SHA that was checked out'
commit:
description: 'The commit SHA that was checked out'
runs:
using: node12
using: node20
main: dist/index.js
post: dist/index.js

View File

@ -1,290 +1,274 @@
# ADR 0153: Checkout v2
**Date**: 2019-10-21
**日期**: 2019-10-21
**Status**: Accepted
**状态**: 已接受
## Context
## 背景
This ADR details the behavior for `actions/checkout@v2`.
ADR 详细说明了 `actions/checkout@v2` 的行为。
The new action will be written in typescript. We are moving away from runner-plugin actions.
新操作将用 TypeScript 编写。我们将不再使用运行器插件操作。
We want to take this opportunity to make behavioral changes, from v1. This document is scoped to those differences.
我们希望借此机会从 v1 进行行为变更。本文档的范围仅限于这些差异。
## Decision
## 决策
### Inputs
### 输入参数
```yaml
repository:
description: 'Repository name with owner. For example, actions/checkout'
default: ${{ github.repository }}
描述: '仓库名称及所有者。例如,actions/checkout'
默认值: ${{ github.repository }}
ref:
description: >
The branch, tag or SHA to checkout. When checking out the repository that
triggered a workflow, this defaults to the reference or SHA for that
event. Otherwise, defaults to `master`.
描述: >
要检出的分支、标签或 SHA。当检出触发工作流的仓库时,默认为该事件的引用或 SHA。
否则,使用默认分支。
token:
description: >
Personal access token (PAT) used to fetch the repository. The PAT is configured
with the local git config, which enables your scripts to run authenticated git
commands. The post-job step removes the PAT.
描述: >
用于获取仓库的个人访问令牌 (PAT)。该 PAT 会配置到本地 git 配置中,使您的脚本可以运行经过身份验证的 git 命令。
作业后步骤会移除该 PAT。
我们建议使用具有最低必要权限的服务账户。
此外,在生成新的 PAT 时,请选择最低必要的范围。
We recommend using a service account with the least permissions necessary.
Also when generating a new PAT, select the least scopes necessary.
[Learn more about creating and using encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
default: ${{ github.token }}
[了解有关创建和使用加密机密的更多信息](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
默认值: ${{ github.token }}
ssh-key:
description: >
SSH key used to fetch the repository. The SSH key is configured with the local
git config, which enables your scripts to run authenticated git commands.
The post-job step removes the SSH key.
描述: >
用于获取仓库的 SSH 密钥。该 SSH 密钥会配置到本地 git 配置中,使您的脚本可以运行经过身份验证的 git 命令。
作业后步骤会移除该 SSH 密钥。
我们建议使用具有最低必要权限的服务账户。
We recommend using a service account with the least permissions necessary.
[Learn more about creating and using
encrypted secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
[了解有关创建和使用加密机密的更多信息](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)
ssh-known-hosts:
description: >
Known hosts in addition to the user and global host key database. The public
SSH keys for a host may be obtained using the utility `ssh-keyscan`. For example,
`ssh-keyscan github.com`. The public key for github.com is always implicitly added.
描述: >
除用户和全局主机密钥数据库之外的已知主机。可以使用 `ssh-keyscan` 工具获取主机的公共 SSH 密钥。例如,`ssh-keyscan github.com`。
github.com 的公钥始终会隐式添加。
ssh-strict:
description: >
Whether to perform strict host key checking. When true, adds the options `StrictHostKeyChecking=yes`
and `CheckHostIP=no` to the SSH command line. Use the input `ssh-known-hosts` to
configure additional hosts.
default: true
描述: >
是否执行严格的主机密钥检查。当为 true 时,会在 SSH 命令行中添加 `StrictHostKeyChecking=yes` 和 `CheckHostIP=no` 选项。
使用 `ssh-known-hosts` 输入来配置其他主机。
默认值: true
persist-credentials:
description: 'Whether to configure the token or SSH key with the local git config'
default: true
描述: '是否将令牌或 SSH 密钥配置到本地 git 配置中'
默认值: true
path:
description: 'Relative path under $GITHUB_WORKSPACE to place the repository'
描述: '在 $GITHUB_WORKSPACE 下放置仓库的相对路径'
clean:
description: 'Whether to execute `git clean -ffdx && git reset --hard HEAD` before fetching'
default: true
描述: '是否在获取前执行 `git clean -ffdx && git reset --hard HEAD`'
默认值: true
fetch-depth:
description: 'Number of commits to fetch. 0 indicates all history for all tags and branches.'
default: 1
描述: '要获取的提交数量。0 表示所有分支和标签的所有历史记录。'
默认值: 1
lfs:
description: 'Whether to download Git-LFS files'
default: false
描述: '是否下载 Git-LFS 文件'
默认值: false
submodules:
description: >
Whether to checkout submodules: `true` to checkout submodules or `recursive` to
recursively checkout submodules.
描述: >
是否检出子模块:`true` 表示检出子模块,`recursive` 表示递归检出子模块。
When the `ssh-key` input is not provided, SSH URLs beginning with `git@github.com:` are
converted to HTTPS.
default: false
当未提供 `ssh-key` 输入时,以 `git@github.com:` 开头的 SSH URL 会被转换为 HTTPS。
默认值: false
```
Note:
- SSH support is new
- `persist-credentials` is new
- `path` behavior is different (refer [below](#path) for details)
注意:
- 新增 SSH 支持
- 新增 `persist-credentials` 参数
- `path` 行为不同(详见下文 [path](#path))
### Fallback to GitHub API
### 回退到 GitHub API
When a sufficient version of git is not in the PATH, fallback to the [web API](https://developer.github.com/v3/repos/contents/#get-archive-link) to download a tarball/zipball.
当 PATH 中没有足够版本的 git 时,回退到 [Web API](https://developer.github.com/v3/repos/contents/#get-archive-link) 下载 tarball/zipball
Note:
- LFS files are not included in the archive. Therefore fail if LFS is set to true.
- Submodules are also not included in the archive.
注意:
- 存档中不包含 LFS 文件。因此,如果 LFS 设置为 true,则会失败。
- 存档中也不包含子模块。
### Persist credentials
### 持久化凭据
The credentials will be persisted on disk. This will allow users to script authenticated git commands, like `git fetch`.
凭据将持久化到磁盘。这将允许用户编写经过身份验证的 git 命令脚本,如 `git fetch`
A post script will remove the credentials (cleanup for self-hosted).
作业后脚本将移除凭据(自托管环境的清理)。
Users may opt-out by specifying `persist-credentials: false`
用户可以通过指定 `persist-credentials: false` 选择退出
Note:
- Users scripting `git commit` may need to set the username and email. The service does not provide any reasonable default value. Users can add `git config user.name <NAME>` and `git config user.email <EMAIL>`. We will document this guidance.
注意:
- 编写 `git commit` 脚本的用户可能需要设置用户名和电子邮件。服务不会提供任何合理的默认值。用户可以添加 `git config user.name <NAME>` `git config user.email <EMAIL>`。我们将记录此指导。
#### PAT
When using the `${{github.token}}` or a PAT, the token will be persisted in the local git config. The config key `http.https://github.com/.extraheader` enables an auth header to be specified on all authenticated commands `AUTHORIZATION: basic <BASE64_U:P>`.
使用 `${{github.token}}` 或 PAT 时,令牌将持久化到本地 git 配置中。配置键 `http.https://github.com/.extraheader` 允许在所有经过身份验证的命令上指定 auth header `AUTHORIZATION: basic <BASE64_U:P>`
Note:
- The auth header is scoped to all of github `http.https://github.com/.extraheader`
- Additional public remotes also just work.
- If users want to authenticate to an additional private remote, they should provide the `token` input.
注意:
- auth header 的范围限定在所有 github `http.https://github.com/.extraheader`
- 额外的公共远程仓库也能正常工作。
- 如果用户需要对额外的私有远程仓库进行身份验证,他们应提供 `token` 输入。
#### SSH key
#### SSH 密钥
The SSH key will be written to disk under the `$RUNNER_TEMP` directory. The SSH key will
be removed by the action's post-job hook. Additionally, RUNNER_TEMP is cleared by the
runner between jobs.
SSH 密钥将写入 `$RUNNER_TEMP` 目录下的磁盘。SSH 密钥将由操作的作业后钩子移除。此外,RUNNER_TEMP 在作业之间会被运行器清除。
The SSH key must be written with strict file permissions. The SSH client requires the file
to be read/write for the user, and not accessible by others.
SSH 密钥必须以严格的文件权限写入。SSH 客户端要求文件对用户可读/写,且其他用户无法访问。
The user host key database (`~/.ssh/known_hosts`) will be copied to a unique file under
`$RUNNER_TEMP`. And values from the input `ssh-known-hosts` will be added to the file.
用户主机密钥数据库 (`~/.ssh/known_hosts`) 将被复制到 `$RUNNER_TEMP` 下的唯一文件中。输入 `ssh-known-hosts` 的值将被添加到该文件中。
The SSH command will be overridden for the local git config:
SSH 命令将覆盖本地 git 配置:
```sh
git config core.sshCommand 'ssh -i "$RUNNER_TEMP/path-to-ssh-key" -o StrictHostKeyChecking=yes -o CheckHostIP=no -o "UserKnownHostsFile=$RUNNER_TEMP/path-to-known-hosts"'
```
When the input `ssh-strict` is set to `false`, the options `CheckHostIP` and `StrictHostKeyChecking` will not be overridden.
当输入 `ssh-strict` 设置为 `false` 时,选项 `CheckHostIP` `StrictHostKeyChecking` 将不会被覆盖。
Note:
- When `ssh-strict` is set to `true` (default), the SSH option `CheckHostIP` can safely be disabled.
Strict host checking verifies the server's public key. Therefore, IP verification is unnecessary
and noisy. For example:
> Warning: Permanently added the RSA host key for IP address '140.82.113.4' to the list of known hosts.
- Since GIT_SSH_COMMAND overrides core.sshCommand, temporarily set the env var when fetching the repo. When creds
are persisted, core.sshCommand is leveraged to avoid multiple checkout steps stomping over each other.
- Modify actions/runner to mount RUNNER_TEMP to enable scripting authenticated git commands from a container action.
- Refer [here](https://linux.die.net/man/5/ssh_config) for SSH config details.
注意:
- `ssh-strict` 设置为 `true`(默认值)时,可以安全地禁用 SSH 选项 `CheckHostIP`
严格的主机检查会验证服务器的公钥。因此,IP 验证是不必要的,并且会产生噪音。例如:
> 警告:已将 RSA 主机密钥永久添加到已知主机列表中,IP 地址为 '140.82.113.4'。
- 由于 GIT_SSH_COMMAND 会覆盖 core.sshCommand,因此在获取仓库时会临时设置环境变量。当凭据被持久化时,core.sshCommand 将被利用以避免多个检出步骤相互覆盖。
- 修改 actions/runner 以挂载 RUNNER_TEMP,从而允许从容器操作中编写经过身份验证的 git 命令脚本。
- 有关 SSH 配置详细信息,请参阅 [这里](https://linux.die.net/man/5/ssh_config)。
### Fetch behavior
### 获取行为
Fetch only the SHA being built and set depth=1. This significantly reduces the fetch time for large repos.
仅获取正在构建的 SHA 并将深度设置为 1。这显著减少了大型仓库的获取时间。
If a SHA isn't available (e.g. multi repo), then fetch only the specified ref with depth=1.
如果 SHA 不可用(例如多仓库),则仅获取指定的 ref,深度为 1。
The input `fetch-depth` can be used to control the depth.
可以使用输入 `fetch-depth` 控制深度。
Note:
- Fetching a single commit is supported by Git wire protocol version 2. The git client uses protocol version 0 by default. The desired protocol version can be overridden in the git config or on the fetch command line invocation (`-c protocol.version=2`). We will override on the fetch command line, for transparency.
- Git client version 2.18+ (released June 2018) is required for wire protocol version 2.
注意:
- Git 线路协议版本 2 支持获取单个提交。git 客户端默认使用协议版本 0。可以在 git 配置中或在 fetch 命令行调用时覆盖所需的协议版本(`-c protocol.version=2`)。我们将在 fetch 命令行上覆盖,以确保透明性。
- Git 客户端版本 2.18+(2018 年 6 月发布)需要线路协议版本 2
### Checkout behavior
### 检出行为
For CI, checkout will create a local ref with the upstream set. This allows users to script git as they normally would.
对于 CI,检出将创建一个设置了上游的本地引用。这允许用户像平常一样编写 git 脚本。
For PR, continue to checkout detached head. The PR branch is special - the branch and merge commit are created by the server. It doesn't match a users' local workflow.
对于 PR,继续检出分离的 HEAD。PR 分支是特殊的 - 分支和合并提交由服务器创建。它不匹配用户的本地工作流。
Note:
- Consider deleting all local refs during cleanup if that helps avoid collisions. More testing required.
注意:
- 如果有助于避免冲突,可以考虑在清理时删除所有本地引用。需要更多测试。
### Path
### 路径
For the mainline scenario, the disk-layout behavior remains the same.
对于主线场景,磁盘布局行为保持不变。
Remember, given the repo `johndoe/foo`, the mainline disk layout looks like:
记住,对于仓库 `johndoe/foo`,主线磁盘布局如下:
```
GITHUB_WORKSPACE=/home/runner/work/foo/foo
RUNNER_WORKSPACE=/home/runner/work/foo
```
V2 introduces a new contraint on the checkout path. The location must now be under `github.workspace`. Whereas the checkout@v1 constraint was one level up, under `runner.workspace`.
V2 对检出路径引入了新的约束。位置现在必须在 `github.workspace` 下。而 checkout@v1 的约束是在上一级,位于 `runner.workspace` 下。
V2 no longer changes `github.workspace` to follow wherever the self repo is checked-out.
V2 不再更改 `github.workspace` 以跟随自仓库的检出位置。
These behavioral changes align better with container actions. The [documented filesystem contract](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#docker-container-filesystem) is:
这些行为变化更好地与容器操作对齐。[记录的文件系统契约](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#docker-container-filesystem) 是:
- `/github/home`
- `/github/workspace` - Note: GitHub Actions must be run by the default Docker user (root). Ensure your Dockerfile does not set the USER instruction, otherwise you will not be able to access `GITHUB_WORKSPACE`.
- `/github/workspace` - 注意:GitHub Actions 必须由默认的 Docker 用户(root)运行。确保您的 Dockerfile 没有设置 USER 指令,否则您将无法访问 `GITHUB_WORKSPACE`
- `/github/workflow`
Note:
- The tracking config will not be updated to reflect the path of the workflow repo.
- Any existing workflow repo will not be moved when the checkout path changes. In fact some customers want to checkout the workflow repo twice, side by side against different branches.
- Actions that need to operate only against the root of the self repo, should expose a `path` input.
注意:
- 跟踪配置不会更新以反映工作流仓库的路径。
- 当检出路径更改时,任何现有的工作流仓库都不会被移动。实际上,一些客户希望并行检出工作流仓库到不同分支的旁边。
- 需要仅针对自仓库的根目录操作的 Actions 应公开一个 `path` 输入。
#### Default value for `path` input
#### `path` 输入的默认值
The `path` input will default to `./` which is rooted against `github.workspace`.
`path` 输入将默认为 `./`,相对于 `github.workspace`
This default fits the mainline scenario well: single checkout
此默认值非常适合主线场景:单一检出
For multi-checkout, users must specify the `path` input for at least one of the repositories.
对于多检出,用户必须至少为一个仓库指定 `path` 输入。
Note:
- An alternative is for the self repo to default to `./` and other repos default to `<REPO_NAME>`. However nested layout is an atypical git layout and therefore is not a good default. Users should supply the path info.
注意:
- 另一种选择是自仓库默认为 `./`,其他仓库默认为 `<REPO_NAME>`。然而,嵌套布局是一种非典型的 git 布局,因此不是好的默认值。用户应提供路径信息。
#### Example - Nested layout
#### 示例 - 嵌套布局
The following example checks-out two repositories and creates a nested layout.
以下示例检出两个仓库并创建嵌套布局。
```yaml
# Self repo - Checkout to $GITHUB_WORKSPACE
- uses: checkout@v2
自仓库 - 检出到 $GITHUB_WORKSPACE
uses: checkout@v2
其他仓库 - 检出到 $GITHUB_WORKSPACE/myscripts
• uses: checkout@v2
# Other repo - Checkout to $GITHUB_WORKSPACE/myscripts
- uses: checkout@v2
with:
repository: myorg/myscripts
path: myscripts
```
#### Example - Side by side layout
#### 示例 - 并排布局
The following example checks-out two repositories and creates a side-by-side layout.
以下示例检出两个仓库并创建并排布局。
```yaml
# Self repo - Checkout to $GITHUB_WORKSPACE/foo
- uses: checkout@v2
自仓库 - 检出到 $GITHUB_WORKSPACE/foo
uses: checkout@v2
with:
path: foo
# Other repo - Checkout to $GITHUB_WORKSPACE/myscripts
- uses: checkout@v2
其他仓库 - 检出到 $GITHUB_WORKSPACE/myscripts
uses: checkout@v2
with:
repository: myorg/myscripts
path: myscripts
```
#### Path impact to problem matchers
#### 路径对问题匹配器的影响
Problem matchers associate the source files with annotations.
问题匹配器将源文件与注释关联。
Today the runner verifies the source file is under the `github.workspace`. Otherwise the source file property is dropped.
目前,运行器验证源文件是否在 `github.workspace` 下。否则,源文件属性将被丢弃。
Multi-checkout complicates the matter. However even today submodules may cause this heuristic to be inaccurate.
多检出使问题复杂化。然而,即使是现在,子模块也可能导致此启发式不准确。
A better solution is:
更好的解决方案是:
Given a source file path, walk up the directories until the first `.git/config` is found. Check if it matches the self repo (`url = https://github.com/OWNER/REPO`). If not, drop the source file path.
给定源文件路径,向上遍历目录,直到找到第一个 `.git/config`。检查它是否与自仓库匹配(`url = https://github.com/OWNER/REPO`)。如果不匹配,则丢弃源文件路径。
### Submodules
### 子模块
With both PAT and SSH key support, we should be able to provide frictionless support for
submodules scenarios: recursive, non-recursive, relative submodule paths.
有了 PAT SSH 密钥支持,我们应该能够为子模块场景提供无缝支持:递归、非递归、相对子模块路径。
When fetching submodules, follow the `fetch-depth` settings.
获取子模块时,遵循 `fetch-depth` 设置。
Also when fetching submodules, if the `ssh-key` input is not provided then convert SSH URLs to HTTPS: `-c url."https://github.com/".insteadOf "git@github.com:"`
此外,在获取子模块时,如果未提供 `ssh-key` 输入,则将 SSH URL 转换为 HTTPS`-c url."https://github.com/".insteadOf "git@github.com:"`
Credentials will be persisted in the submodules local git config too.
凭据也将持久化到子模块的本地 git 配置中。
### Port to typescript
### 转换为 TypeScript
The checkout action should be a typescript action on the GitHub graph, for the following reasons:
- Enables customers to fork the checkout repo and modify
- Serves as an example for customers
- Demystifies the checkout action manifest
- Simplifies the runner
- Reduce the amount of runner code to port (if we ever do)
出于以下原因,检出操作应该是 GitHub graph 上的 TypeScript 操作:
- 使客户能够 fork 检出仓库并进行修改
- 作为客户的示例
- 澄清检出操作清单
- 简化运行器
- 减少需要移植的运行器代码量(如果我们曾经这样做)
Note:
- This means job-container images will need git in the PATH, for checkout.
注意:
- 这意味着作业容器镜像需要在 PATH 中有 git,以便进行检出。
### Branching strategy and release tags
### 分支策略和发布标签
- Create a servicing branch for V1: `releases/v1`
- Merge the changes into `master`
- Release using a new tag `preview`
- When stable, release using a new tag `v2`
- 为 V1 创建一个维护分支:`releases/v1`
- 将更改合并到默认分支
- 使用新标签 `preview` 发布
- 稳定后,使用新标签 `v2` 发布
## Consequences
## 后果
- Update the checkout action and readme
- Update samples to consume `actions/checkout@v2`
- Job containers now require git in the PATH for checkout, otherwise fallback to REST API
- Minimum git version 2.18
- Update problem matcher logic regarding source file verification (runner)
- 更新检出操作和自述文件
- 更新示例以使用 `actions/checkout@v2`
- 作业容器现在需要 PATH 中有 git 才能进行检出,否则回退到 REST API
- 最低 git 版本 2.18
- 更新问题匹配器逻辑,关于源文件验证(运行器)

63538
dist/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
# Defines the test-ubuntu-git Container Image.
# Consumed by actions/checkout CI/CD validation workflows.
FROM ubuntu:latest
RUN apt update
RUN apt install -y git
LABEL org.opencontainers.image.title="Ubuntu + git (validation image)"
LABEL org.opencontainers.image.description="Ubuntu image with git pre-installed. Intended primarily for testing `actions/checkout` during CI/CD workflows."
LABEL org.opencontainers.image.documentation="https://github.com/actions/checkout/tree/main/images/test-ubuntu-git.md"
LABEL org.opencontainers.image.licenses=MIT

15
images/test-ubuntu-git.md Normal file
View File

@ -0,0 +1,15 @@
# `test-ubuntu-git` Container Image
[![Publish test-ubuntu-git Container](https://github.com/actions/checkout/actions/workflows/update-test-ubuntu-git.yml/badge.svg)](https://github.com/actions/checkout/actions/workflows/update-test-ubuntu-git.yml)
## Purpose
`test-ubuntu-git` is a container image hosted on the GitHub Container Registry, `ghcr.io`.
It is intended primarily for testing the [`actions/checkout` repository](https://github.com/actions/checkout) as part of `actions/checkout`'s CI/CD workflows.
The composition of `test-ubuntu-git` is intentionally minimal. It is comprised of [git](https://git-scm.com/) installed on top of a [base-level ubuntu image](https://hub.docker.com/_/ubuntu/tags).
# License
`test-ubuntu-git` is released under the [MIT License](/LICENSE).

View File

@ -1,5 +1,6 @@
module.exports = {
clearMocks: true,
fakeTimers: {},
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],

12679
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "checkout",
"version": "2.0.2",
"version": "4.2.2",
"description": "checkout action",
"main": "lib/main.js",
"scripts": {
@ -8,7 +8,9 @@
"format": "prettier --write '**/*.ts'",
"format-check": "prettier --check '**/*.ts'",
"lint": "eslint src/**/*.ts",
"test": "jest"
"test": "jest",
"licensed-check": "src/misc/licensed-check.sh",
"licensed-generate": "src/misc/licensed-generate.sh"
},
"repository": {
"type": "git",
@ -26,27 +28,28 @@
},
"homepage": "https://github.com/actions/checkout#readme",
"dependencies": {
"@actions/core": "^1.1.3",
"@actions/exec": "^1.0.1",
"@actions/github": "^2.2.0",
"@actions/io": "^1.0.1",
"@actions/tool-cache": "^1.1.2",
"uuid": "^3.3.3"
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.0",
"@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1",
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/jest": "^24.0.23",
"@types/node": "^12.7.12",
"@types/uuid": "^3.4.6",
"@typescript-eslint/parser": "^2.8.0",
"@zeit/ncc": "^0.20.5",
"eslint": "^5.16.0",
"eslint-plugin-github": "^2.0.0",
"eslint-plugin-jest": "^22.21.0",
"jest": "^24.9.0",
"jest-circus": "^24.9.0",
"js-yaml": "^3.13.1",
"prettier": "^1.19.1",
"ts-jest": "^24.2.0",
"typescript": "^3.6.4"
"@types/jest": "^29.5.12",
"@types/node": "^20.12.12",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^7.9.0",
"@typescript-eslint/parser": "^7.9.0",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0",
"eslint-plugin-github": "^4.10.2",
"eslint-plugin-jest": "^28.8.2",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"js-yaml": "^4.1.0",
"prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"typescript": "^5.5.4"
}
}

View File

@ -9,7 +9,7 @@ export function directoryExistsSync(path: string, required?: boolean): boolean {
try {
stats = fs.statSync(path)
} catch (error) {
if (error.code === 'ENOENT') {
if ((error as any)?.code === 'ENOENT') {
if (!required) {
return false
}
@ -18,7 +18,9 @@ export function directoryExistsSync(path: string, required?: boolean): boolean {
}
throw new Error(
`Encountered an error when checking whether path '${path}' exists: ${error.message}`
`Encountered an error when checking whether path '${path}' exists: ${
(error as any)?.message ?? error
}`
)
}
@ -39,12 +41,14 @@ export function existsSync(path: string): boolean {
try {
fs.statSync(path)
} catch (error) {
if (error.code === 'ENOENT') {
if ((error as any)?.code === 'ENOENT') {
return false
}
throw new Error(
`Encountered an error when checking whether path '${path}' exists: ${error.message}`
`Encountered an error when checking whether path '${path}' exists: ${
(error as any)?.message ?? error
}`
)
}
@ -60,12 +64,14 @@ export function fileExistsSync(path: string): boolean {
try {
stats = fs.statSync(path)
} catch (error) {
if (error.code === 'ENOENT') {
if ((error as any)?.code === 'ENOENT') {
return false
}
throw new Error(
`Encountered an error when checking whether path '${path}' exists: ${error.message}`
`Encountered an error when checking whether path '${path}' exists: ${
(error as any)?.message ?? error
}`
)
}

View File

@ -8,7 +8,7 @@ import * as path from 'path'
import * as regexpHelper from './regexp-helper'
import * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {default as uuid} from 'uuid/v4'
import {v4 as uuid} from 'uuid'
import {IGitCommandManager} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
@ -19,8 +19,9 @@ export interface IGitAuthHelper {
configureAuth(): Promise<void>
configureGlobalAuth(): Promise<void>
configureSubmoduleAuth(): Promise<void>
configureTempGlobalConfig(): Promise<string>
removeAuth(): Promise<void>
removeGlobalAuth(): Promise<void>
removeGlobalConfig(): Promise<void>
}
export function createAuthHelper(
@ -37,7 +38,7 @@ class GitAuthHelper {
private readonly tokenConfigValue: string
private readonly tokenPlaceholderConfigValue: string
private readonly insteadOfKey: string
private readonly insteadOfValue: string
private readonly insteadOfValues: string[] = []
private sshCommand = ''
private sshKeyPath = ''
private sshKnownHostsPath = ''
@ -45,13 +46,13 @@ class GitAuthHelper {
constructor(
gitCommandManager: IGitCommandManager,
gitSourceSettings?: IGitSourceSettings
gitSourceSettings: IGitSourceSettings | undefined
) {
this.git = gitCommandManager
this.settings = gitSourceSettings || (({} as unknown) as IGitSourceSettings)
this.settings = gitSourceSettings || ({} as unknown as IGitSourceSettings)
// Token auth header
const serverUrl = urlHelper.getServerUrl()
const serverUrl = urlHelper.getServerUrl(this.settings.githubServerUrl)
this.tokenConfigKey = `http.${serverUrl.origin}/.extraheader` // "origin" is SCHEME://HOSTNAME[:PORT]
const basicCredential = Buffer.from(
`x-access-token:${this.settings.authToken}`,
@ -63,7 +64,12 @@ class GitAuthHelper {
// Instead of SSH URL
this.insteadOfKey = `url.${serverUrl.origin}/.insteadOf` // "origin" is SCHEME://HOSTNAME[:PORT]
this.insteadOfValue = `git@${serverUrl.hostname}:`
this.insteadOfValues.push(`git@${serverUrl.hostname}:`)
if (this.settings.workflowOrganizationId) {
this.insteadOfValues.push(
`org-${this.settings.workflowOrganizationId}@github.com:`
)
}
}
async configureAuth(): Promise<void> {
@ -75,7 +81,11 @@ class GitAuthHelper {
await this.configureToken()
}
async configureGlobalAuth(): Promise<void> {
async configureTempGlobalConfig(): Promise<string> {
// Already setup global config
if (this.temporaryHomePath?.length > 0) {
return path.join(this.temporaryHomePath, '.gitconfig')
}
// Create a temp home directory
const runnerTemp = process.env['RUNNER_TEMP'] || ''
assert.ok(runnerTemp, 'RUNNER_TEMP is not defined')
@ -94,7 +104,7 @@ class GitAuthHelper {
await fs.promises.stat(gitConfigPath)
configExists = true
} catch (err) {
if (err.code !== 'ENOENT') {
if ((err as any)?.code !== 'ENOENT') {
throw err
}
}
@ -105,20 +115,28 @@ class GitAuthHelper {
await fs.promises.writeFile(newGitConfigPath, '')
}
try {
// Override HOME
core.info(
`Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes`
)
this.git.setEnvironmentVariable('HOME', this.temporaryHomePath)
// Override HOME
core.info(
`Temporarily overriding HOME='${this.temporaryHomePath}' before making global git config changes`
)
this.git.setEnvironmentVariable('HOME', this.temporaryHomePath)
return newGitConfigPath
}
async configureGlobalAuth(): Promise<void> {
// 'configureTempGlobalConfig' noops if already set, just returns the path
const newGitConfigPath = await this.configureTempGlobalConfig()
try {
// Configure the token
await this.configureToken(newGitConfigPath, true)
// Configure HTTPS instead of SSH
await this.git.tryConfigUnset(this.insteadOfKey, true)
if (!this.settings.sshKey) {
await this.git.config(this.insteadOfKey, this.insteadOfValue, true)
for (const insteadOfValue of this.insteadOfValues) {
await this.git.config(this.insteadOfKey, insteadOfValue, true, true)
}
}
} catch (err) {
// Unset in case somehow written to the real global config
@ -139,7 +157,8 @@ class GitAuthHelper {
// by process creation audit events, which are commonly logged. For more information,
// refer to https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
const output = await this.git.submoduleForeach(
`git config --local '${this.tokenConfigKey}' '${this.tokenPlaceholderConfigValue}' && git config --local --show-origin --name-only --get-regexp remote.origin.url`,
// wrap the pipeline in quotes to make sure it's handled properly by submoduleForeach, rather than just the first part of the pipeline
`sh -c "git config --local '${this.tokenConfigKey}' '${this.tokenPlaceholderConfigValue}' && git config --local --show-origin --name-only --get-regexp remote.origin.url"`,
this.settings.nestedSubmodules
)
@ -148,7 +167,7 @@ class GitAuthHelper {
output.match(/(?<=(^|\n)file:)[^\t]+(?=\tremote\.origin\.url)/g) || []
for (const configPath of configPaths) {
core.debug(`Replacing token placeholder in '${configPath}'`)
this.replaceTokenPlaceholder(configPath)
await this.replaceTokenPlaceholder(configPath)
}
if (this.settings.sshKey) {
@ -159,10 +178,12 @@ class GitAuthHelper {
)
} else {
// Configure HTTPS instead of SSH
await this.git.submoduleForeach(
`git config --local '${this.insteadOfKey}' '${this.insteadOfValue}'`,
this.settings.nestedSubmodules
)
for (const insteadOfValue of this.insteadOfValues) {
await this.git.submoduleForeach(
`git config --local --add '${this.insteadOfKey}' '${insteadOfValue}'`,
this.settings.nestedSubmodules
)
}
}
}
}
@ -172,10 +193,12 @@ class GitAuthHelper {
await this.removeToken()
}
async removeGlobalAuth(): Promise<void> {
core.debug(`Unsetting HOME override`)
this.git.removeEnvironmentVariable('HOME')
await io.rmRF(this.temporaryHomePath)
async removeGlobalConfig(): Promise<void> {
if (this.temporaryHomePath?.length > 0) {
core.debug(`Unsetting HOME override`)
this.git.removeEnvironmentVariable('HOME')
await io.rmRF(this.temporaryHomePath)
}
}
private async configureSsh(): Promise<void> {
@ -213,7 +236,7 @@ class GitAuthHelper {
await fs.promises.readFile(userKnownHostsPath)
).toString()
} catch (err) {
if (err.code !== 'ENOENT') {
if ((err as any)?.code !== 'ENOENT') {
throw err
}
}
@ -224,7 +247,7 @@ class GitAuthHelper {
if (this.settings.sshKnownHosts) {
knownHosts += `# Begin from input known hosts\n${this.settings.sshKnownHosts}\n# end from input known hosts\n`
}
knownHosts += `# Begin implicitly added github.com\ngithub.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==\n# End implicitly added github.com\n`
knownHosts += `# Begin implicitly added github.com\ngithub.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=\n# End implicitly added github.com\n`
this.sshKnownHostsPath = path.join(runnerTemp, `${uniqueId}_known_hosts`)
stateHelper.setSshKnownHostsPath(this.sshKnownHostsPath)
await fs.promises.writeFile(this.sshKnownHostsPath, knownHosts)
@ -302,7 +325,7 @@ class GitAuthHelper {
try {
await io.rmRF(keyPath)
} catch (err) {
core.debug(err.message)
core.debug(`${(err as any)?.message ?? err}`)
core.warning(`Failed to remove SSH key '${keyPath}'`)
}
}
@ -343,7 +366,8 @@ class GitAuthHelper {
const pattern = regexpHelper.escape(configKey)
await this.git.submoduleForeach(
`git config --local --name-only --get-regexp '${pattern}' && git config --local --unset-all '${configKey}' || :`,
// wrap the pipeline in quotes to make sure it's handled properly by submoduleForeach, rather than just the first part of the pipeline
`sh -c "git config --local --name-only --get-regexp '${pattern}' && git config --local --unset-all '${configKey}' || :"`,
true
)
}

View File

@ -1,5 +1,6 @@
import * as core from '@actions/core'
import * as exec from '@actions/exec'
import * as fs from 'fs'
import * as fshelper from './fs-helper'
import * as io from '@actions/io'
import * as path from 'path'
@ -10,27 +11,42 @@ import {GitVersion} from './git-version'
// Auth header not supported before 2.9
// Wire protocol v2 not supported before 2.18
// sparse-checkout not [well-]supported before 2.28 (see https://github.com/actions/checkout/issues/1386)
export const MinimumGitVersion = new GitVersion('2.18')
export const MinimumGitSparseCheckoutVersion = new GitVersion('2.28')
export interface IGitCommandManager {
branchDelete(remote: boolean, branch: string): Promise<void>
branchExists(remote: boolean, pattern: string): Promise<boolean>
branchList(remote: boolean): Promise<string[]>
disableSparseCheckout(): Promise<void>
sparseCheckout(sparseCheckout: string[]): Promise<void>
sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void>
checkout(ref: string, startPoint: string): Promise<void>
checkoutDetach(): Promise<void>
config(
configKey: string,
configValue: string,
globalConfig?: boolean
globalConfig?: boolean,
add?: boolean
): Promise<void>
configExists(configKey: string, globalConfig?: boolean): Promise<boolean>
fetch(refSpec: string[], fetchDepth?: number): Promise<void>
fetch(
refSpec: string[],
options: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
}
): Promise<void>
getDefaultBranch(repositoryUrl: string): Promise<string>
getWorkingDirectory(): string
init(): Promise<void>
isDetached(): Promise<boolean>
lfsFetch(ref: string): Promise<void>
lfsInstall(): Promise<void>
log1(): Promise<string>
log1(format?: string): Promise<string>
remoteAdd(remoteName: string, remoteUrl: string): Promise<void>
removeEnvironmentVariable(name: string): void
revParse(ref: string): Promise<string>
@ -39,19 +55,26 @@ export interface IGitCommandManager {
submoduleForeach(command: string, recursive: boolean): Promise<string>
submoduleSync(recursive: boolean): Promise<void>
submoduleUpdate(fetchDepth: number, recursive: boolean): Promise<void>
submoduleStatus(): Promise<boolean>
tagExists(pattern: string): Promise<boolean>
tryClean(): Promise<boolean>
tryConfigUnset(configKey: string, globalConfig?: boolean): Promise<boolean>
tryDisableAutomaticGarbageCollection(): Promise<boolean>
tryGetFetchUrl(): Promise<string>
tryReset(): Promise<boolean>
version(): Promise<GitVersion>
}
export async function createCommandManager(
workingDirectory: string,
lfs: boolean
lfs: boolean,
doSparseCheckout: boolean
): Promise<IGitCommandManager> {
return await GitCommandManager.createCommandManager(workingDirectory, lfs)
return await GitCommandManager.createCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
}
class GitCommandManager {
@ -61,7 +84,9 @@ class GitCommandManager {
}
private gitPath = ''
private lfs = false
private doSparseCheckout = false
private workingDirectory = ''
private gitVersion: GitVersion = new GitVersion()
// Private constructor; use createCommandManager()
private constructor() {}
@ -92,8 +117,11 @@ class GitCommandManager {
// Note, this implementation uses "rev-parse --symbolic-full-name" because the output from
// "branch --list" is more difficult when in a detached HEAD state.
// Note, this implementation uses "rev-parse --symbolic-full-name" because there is a bug
// in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names.
// TODO(https://github.com/actions/checkout/issues/786): this implementation uses
// "rev-parse --symbolic-full-name" because there is a bug
// in Git 2.18 that causes "rev-parse --symbolic" to output symbolic full names. When
// 2.18 is no longer supported, we can switch back to --symbolic.
const args = ['rev-parse', '--symbolic-full-name']
if (remote) {
@ -102,24 +130,79 @@ class GitCommandManager {
args.push('--branches')
}
const output = await this.execGit(args)
const stderr: string[] = []
const errline: string[] = []
const stdout: string[] = []
const stdline: string[] = []
for (let branch of output.stdout.trim().split('\n')) {
branch = branch.trim()
if (branch) {
if (branch.startsWith('refs/heads/')) {
branch = branch.substr('refs/heads/'.length)
} else if (branch.startsWith('refs/remotes/')) {
branch = branch.substr('refs/remotes/'.length)
}
result.push(branch)
const listeners = {
stderr: (data: Buffer) => {
stderr.push(data.toString())
},
errline: (data: Buffer) => {
errline.push(data.toString())
},
stdout: (data: Buffer) => {
stdout.push(data.toString())
},
stdline: (data: Buffer) => {
stdline.push(data.toString())
}
}
// Suppress the output in order to avoid flooding annotations with innocuous errors.
await this.execGit(args, false, true, listeners)
core.debug(`stderr callback is: ${stderr}`)
core.debug(`errline callback is: ${errline}`)
core.debug(`stdout callback is: ${stdout}`)
core.debug(`stdline callback is: ${stdline}`)
for (let branch of stdline) {
branch = branch.trim()
if (!branch) {
continue
}
if (branch.startsWith('refs/heads/')) {
branch = branch.substring('refs/heads/'.length)
} else if (branch.startsWith('refs/remotes/')) {
branch = branch.substring('refs/remotes/'.length)
}
result.push(branch)
}
return result
}
async disableSparseCheckout(): Promise<void> {
await this.execGit(['sparse-checkout', 'disable'])
// Disabling 'sparse-checkout` leaves behind an undesirable side-effect in config (even in a pristine environment).
await this.tryConfigUnset('extensions.worktreeConfig', false)
}
async sparseCheckout(sparseCheckout: string[]): Promise<void> {
await this.execGit(['sparse-checkout', 'set', ...sparseCheckout])
}
async sparseCheckoutNonConeMode(sparseCheckout: string[]): Promise<void> {
await this.execGit(['config', 'core.sparseCheckout', 'true'])
const output = await this.execGit([
'rev-parse',
'--git-path',
'info/sparse-checkout'
])
const sparseCheckoutPath = path.join(
this.workingDirectory,
output.stdout.trimRight()
)
await fs.promises.appendFile(
sparseCheckoutPath,
`\n${sparseCheckout.join('\n')}\n`
)
}
async checkout(ref: string, startPoint: string): Promise<void> {
const args = ['checkout', '--progress', '--force']
if (startPoint) {
@ -139,14 +222,15 @@ class GitCommandManager {
async config(
configKey: string,
configValue: string,
globalConfig?: boolean
globalConfig?: boolean,
add?: boolean
): Promise<void> {
await this.execGit([
'config',
globalConfig ? '--global' : '--local',
configKey,
configValue
])
const args: string[] = ['config', globalConfig ? '--global' : '--local']
if (add) {
args.push('--add')
}
args.push(...[configKey, configValue])
await this.execGit(args)
}
async configExists(
@ -167,15 +251,31 @@ class GitCommandManager {
return output.exitCode === 0
}
async fetch(refSpec: string[], fetchDepth?: number): Promise<void> {
async fetch(
refSpec: string[],
options: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
}
): Promise<void> {
const args = ['-c', 'protocol.version=2', 'fetch']
if (!refSpec.some(x => x === refHelper.tagsRefSpec)) {
if (!refSpec.some(x => x === refHelper.tagsRefSpec) && !options.fetchTags) {
args.push('--no-tags')
}
args.push('--prune', '--progress', '--no-recurse-submodules')
if (fetchDepth && fetchDepth > 0) {
args.push(`--depth=${fetchDepth}`)
args.push('--prune', '--no-recurse-submodules')
if (options.showProgress) {
args.push('--progress')
}
if (options.filter) {
args.push(`--filter=${options.filter}`)
}
if (options.fetchDepth && options.fetchDepth > 0) {
args.push(`--depth=${options.fetchDepth}`)
} else if (
fshelper.fileExistsSync(
path.join(this.workingDirectory, '.git', 'shallow')
@ -195,6 +295,34 @@ class GitCommandManager {
})
}
async getDefaultBranch(repositoryUrl: string): Promise<string> {
let output: GitOutput | undefined
await retryHelper.execute(async () => {
output = await this.execGit([
'ls-remote',
'--quiet',
'--exit-code',
'--symref',
repositoryUrl,
'HEAD'
])
})
if (output) {
// Satisfy compiler, will always be set
for (let line of output.stdout.trim().split('\n')) {
line = line.trim()
if (line.startsWith('ref:') || line.endsWith('HEAD')) {
return line
.substr('ref:'.length, line.length - 'ref:'.length - 'HEAD'.length)
.trim()
}
}
}
throw new Error('Unexpected output when retrieving default branch')
}
getWorkingDirectory(): string {
return this.workingDirectory
}
@ -225,8 +353,10 @@ class GitCommandManager {
await this.execGit(['lfs', 'install', '--local'])
}
async log1(): Promise<string> {
const output = await this.execGit(['log', '-1'])
async log1(format?: string): Promise<string> {
const args = format ? ['log', '-1', format] : ['log', '-1']
const silent = format ? false : true
const output = await this.execGit(args, false, silent)
return output.stdout
}
@ -241,7 +371,7 @@ class GitCommandManager {
/**
* Resolves a ref to a SHA. For a branch or lightweight tag, the commit SHA is returned.
* For an annotated tag, the tag SHA is returned.
* @param {string} ref For example: 'refs/heads/master' or '/refs/tags/v1'
* @param {string} ref For example: 'refs/heads/main' or '/refs/tags/v1'
* @returns {Promise<string>}
*/
async revParse(ref: string): Promise<string> {
@ -293,6 +423,12 @@ class GitCommandManager {
await this.execGit(args)
}
async submoduleStatus(): Promise<boolean> {
const output = await this.execGit(['submodule', 'status'], true)
core.debug(output.stdout)
return output.exitCode === 0
}
async tagExists(pattern: string): Promise<boolean> {
const output = await this.execGit(['tag', '--list', pattern])
return !!output.stdout.trim()
@ -350,18 +486,29 @@ class GitCommandManager {
return output.exitCode === 0
}
async version(): Promise<GitVersion> {
return this.gitVersion
}
static async createCommandManager(
workingDirectory: string,
lfs: boolean
lfs: boolean,
doSparseCheckout: boolean
): Promise<GitCommandManager> {
const result = new GitCommandManager()
await result.initializeCommandManager(workingDirectory, lfs)
await result.initializeCommandManager(
workingDirectory,
lfs,
doSparseCheckout
)
return result
}
private async execGit(
args: string[],
allowAllExitCodes = false
allowAllExitCodes = false,
silent = false,
customListeners = {}
): Promise<GitOutput> {
fshelper.directoryExistsSync(this.workingDirectory, true)
@ -375,27 +522,36 @@ class GitCommandManager {
env[key] = this.gitEnv[key]
}
const stdout: string[] = []
const defaultListener = {
stdout: (data: Buffer) => {
stdout.push(data.toString())
}
}
const mergedListeners = {...defaultListener, ...customListeners}
const stdout: string[] = []
const options = {
cwd: this.workingDirectory,
env,
silent,
ignoreReturnCode: allowAllExitCodes,
listeners: {
stdout: (data: Buffer) => {
stdout.push(data.toString())
}
}
listeners: mergedListeners
}
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
result.stdout = stdout.join('')
core.debug(result.exitCode.toString())
core.debug(result.stdout)
return result
}
private async initializeCommandManager(
workingDirectory: string,
lfs: boolean
lfs: boolean,
doSparseCheckout: boolean
): Promise<void> {
this.workingDirectory = workingDirectory
@ -410,23 +566,23 @@ class GitCommandManager {
// Git version
core.debug('Getting git version')
let gitVersion = new GitVersion()
this.gitVersion = new GitVersion()
let gitOutput = await this.execGit(['version'])
let stdout = gitOutput.stdout.trim()
if (!stdout.includes('\n')) {
const match = stdout.match(/\d+\.\d+(\.\d+)?/)
if (match) {
gitVersion = new GitVersion(match[0])
this.gitVersion = new GitVersion(match[0])
}
}
if (!gitVersion.isValid()) {
if (!this.gitVersion.isValid()) {
throw new Error('Unable to determine git version')
}
// Minimum git version
if (!gitVersion.checkMinimum(MinimumGitVersion)) {
if (!this.gitVersion.checkMinimum(MinimumGitVersion)) {
throw new Error(
`Minimum required git version is ${MinimumGitVersion}. Your git ('${this.gitPath}') is ${gitVersion}`
`Minimum required git version is ${MinimumGitVersion}. Your git ('${this.gitPath}') is ${this.gitVersion}`
)
}
@ -458,8 +614,16 @@ class GitCommandManager {
}
}
this.doSparseCheckout = doSparseCheckout
if (this.doSparseCheckout) {
if (!this.gitVersion.checkMinimum(MinimumGitSparseCheckoutVersion)) {
throw new Error(
`Minimum Git version required for sparse checkout is ${MinimumGitSparseCheckoutVersion}. Your git ('${this.gitPath}') is ${this.gitVersion}`
)
}
}
// Set the user agent
const gitHttpUserAgent = `git/${gitVersion} (github-actions-checkout)`
const gitHttpUserAgent = `git/${this.gitVersion} (github-actions-checkout)`
core.debug(`Set git useragent to: ${gitHttpUserAgent}`)
this.gitEnv['GIT_HTTP_USER_AGENT'] = gitHttpUserAgent
}

View File

@ -39,7 +39,9 @@ export async function prepareExistingDirectory(
try {
await io.rmRF(lockPath)
} catch (error) {
core.debug(`Unable to delete '${lockPath}'. ${error.message}`)
core.debug(
`Unable to delete '${lockPath}'. ${(error as any)?.message ?? error}`
)
}
}
@ -79,12 +81,18 @@ export async function prepareExistingDirectory(
}
core.endGroup()
// Check for submodules and delete any existing files if submodules are present
if (!(await git.submoduleStatus())) {
remove = true
core.info('Bad Submodules found, removing existing files')
}
// Clean
if (clean) {
core.startGroup('Cleaning the repository')
if (!(await git.tryClean())) {
core.debug(
`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For futher investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
`The clean command failed. This might be caused by: 1) path too long, 2) permission issue, or 3) file in use. For further investigation, manually run 'git clean -ffdx' on the directory '${repositoryPath}'.`
)
remove = true
} else if (!(await git.tryReset())) {

View File

@ -9,7 +9,10 @@ import * as path from 'path'
import * as refHelper from './ref-helper'
import * as stateHelper from './state-helper'
import * as urlHelper from './url-helper'
import {IGitCommandManager} from './git-command-manager'
import {
MinimumGitSparseCheckoutVersion,
IGitCommandManager
} from './git-command-manager'
import {IGitSourceSettings} from './git-source-settings'
export async function getSource(settings: IGitSourceSettings): Promise<void> {
@ -36,73 +39,116 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
const git = await getGitCommandManager(settings)
core.endGroup()
// Prepare existing directory, otherwise recreate
if (isExisting) {
await gitDirectoryHelper.prepareExistingDirectory(
git,
settings.repositoryPath,
repositoryUrl,
settings.clean,
settings.ref
)
}
let authHelper: gitAuthHelper.IGitAuthHelper | null = null
try {
if (git) {
authHelper = gitAuthHelper.createAuthHelper(git, settings)
if (settings.setSafeDirectory) {
// Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
// Otherwise all git commands we run in a container fail
await authHelper.configureTempGlobalConfig()
core.info(
`Adding repository directory to the temporary git global config as a safe directory`
)
if (!git) {
// Downloading using REST API
core.info(`The repository will be downloaded using the GitHub REST API`)
core.info(
`To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH`
)
if (settings.submodules) {
throw new Error(
`Input 'submodules' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.`
)
} else if (settings.sshKey) {
throw new Error(
`Input 'ssh-key' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.`
await git
.config('safe.directory', settings.repositoryPath, true, true)
.catch(error => {
core.info(
`Failed to initialize safe directory with error: ${error}`
)
})
stateHelper.setSafeDirectory()
}
}
// Prepare existing directory, otherwise recreate
if (isExisting) {
await gitDirectoryHelper.prepareExistingDirectory(
git,
settings.repositoryPath,
repositoryUrl,
settings.clean,
settings.ref
)
}
await githubApiHelper.downloadRepository(
settings.authToken,
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
settings.commit,
settings.repositoryPath
)
return
}
if (!git) {
// Downloading using REST API
core.info(`The repository will be downloaded using the GitHub REST API`)
core.info(
`To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH`
)
if (settings.submodules) {
throw new Error(
`Input 'submodules' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.`
)
} else if (settings.sshKey) {
throw new Error(
`Input 'ssh-key' not supported when falling back to download using the GitHub REST API. To create a local Git repository instead, add Git ${gitCommandManager.MinimumGitVersion} or higher to the PATH.`
)
}
// Save state for POST action
stateHelper.setRepositoryPath(settings.repositoryPath)
await githubApiHelper.downloadRepository(
settings.authToken,
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
settings.commit,
settings.repositoryPath,
settings.githubServerUrl
)
return
}
// Initialize the repository
if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) {
core.startGroup('Initializing the repository')
await git.init()
await git.remoteAdd('origin', repositoryUrl)
// Save state for POST action
stateHelper.setRepositoryPath(settings.repositoryPath)
// Initialize the repository
if (
!fsHelper.directoryExistsSync(path.join(settings.repositoryPath, '.git'))
) {
core.startGroup('Initializing the repository')
await git.init()
await git.remoteAdd('origin', repositoryUrl)
core.endGroup()
}
// Disable automatic garbage collection
core.startGroup('Disabling automatic garbage collection')
if (!(await git.tryDisableAutomaticGarbageCollection())) {
core.warning(
`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`
)
}
core.endGroup()
}
// Disable automatic garbage collection
core.startGroup('Disabling automatic garbage collection')
if (!(await git.tryDisableAutomaticGarbageCollection())) {
core.warning(
`Unable to turn off git automatic garbage collection. The git fetch operation may trigger garbage collection and cause a delay.`
)
}
core.endGroup()
const authHelper = gitAuthHelper.createAuthHelper(git, settings)
try {
// If we didn't initialize it above, do it now
if (!authHelper) {
authHelper = gitAuthHelper.createAuthHelper(git, settings)
}
// Configure auth
core.startGroup('Setting up auth')
await authHelper.configureAuth()
core.endGroup()
// Determine the default branch
if (!settings.ref && !settings.commit) {
core.startGroup('Determining the default branch')
if (settings.sshKey) {
settings.ref = await git.getDefaultBranch(repositoryUrl)
} else {
settings.ref = await githubApiHelper.getDefaultBranch(
settings.authToken,
settings.repositoryOwner,
settings.repositoryName,
settings.githubServerUrl
)
}
core.endGroup()
}
// LFS install
if (settings.lfs) {
await git.lfsInstall()
@ -110,23 +156,38 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Fetch
core.startGroup('Fetching the repository')
const fetchOptions: {
filter?: string
fetchDepth?: number
fetchTags?: boolean
showProgress?: boolean
} = {}
if (settings.filter) {
fetchOptions.filter = settings.filter
} else if (settings.sparseCheckout) {
fetchOptions.filter = 'blob:none'
}
if (settings.fetchDepth <= 0) {
// Fetch all branches and tags
let refSpec = refHelper.getRefSpecForAllHistory(
settings.ref,
settings.commit
)
await git.fetch(refSpec)
await git.fetch(refSpec, fetchOptions)
// When all history is fetched, the ref we're interested in may have moved to a different
// commit (push or force push). If so, fetch again with a targeted refspec.
if (!(await refHelper.testRef(git, settings.ref, settings.commit))) {
refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(refSpec)
await git.fetch(refSpec, fetchOptions)
}
} else {
fetchOptions.fetchDepth = settings.fetchDepth
fetchOptions.fetchTags = settings.fetchTags
const refSpec = refHelper.getRefSpec(settings.ref, settings.commit)
await git.fetch(refSpec, settings.fetchDepth)
await git.fetch(refSpec, fetchOptions)
}
core.endGroup()
@ -142,12 +203,30 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// LFS fetch
// Explicit lfs-fetch to avoid slow checkout (fetches one lfs object at a time).
// Explicit lfs fetch will fetch lfs objects in parallel.
if (settings.lfs) {
// For sparse checkouts, let `checkout` fetch the needed objects lazily.
if (settings.lfs && !settings.sparseCheckout) {
core.startGroup('Fetching LFS objects')
await git.lfsFetch(checkoutInfo.startPoint || checkoutInfo.ref)
core.endGroup()
}
// Sparse checkout
if (!settings.sparseCheckout) {
let gitVersion = await git.version()
// no need to disable sparse-checkout if the installed git runtime doesn't even support it.
if (gitVersion.checkMinimum(MinimumGitSparseCheckoutVersion)) {
await git.disableSparseCheckout()
}
} else {
core.startGroup('Setting up sparse checkout')
if (settings.sparseCheckoutConeMode) {
await git.sparseCheckout(settings.sparseCheckout)
} else {
await git.sparseCheckoutNonConeMode(settings.sparseCheckout)
}
core.endGroup()
}
// Checkout
core.startGroup('Checking out the ref')
await git.checkout(checkoutInfo.ref, checkoutInfo.startPoint)
@ -155,40 +234,36 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
// Submodules
if (settings.submodules) {
try {
// Temporarily override global config
core.startGroup('Setting up auth for fetching submodules')
await authHelper.configureGlobalAuth()
core.endGroup()
// Temporarily override global config
core.startGroup('Setting up auth for fetching submodules')
await authHelper.configureGlobalAuth()
core.endGroup()
// Checkout submodules
core.startGroup('Fetching submodules')
await git.submoduleSync(settings.nestedSubmodules)
await git.submoduleUpdate(
settings.fetchDepth,
settings.nestedSubmodules
)
await git.submoduleForeach(
'git config --local gc.auto 0',
settings.nestedSubmodules
)
core.endGroup()
// Checkout submodules
core.startGroup('Fetching submodules')
await git.submoduleSync(settings.nestedSubmodules)
await git.submoduleUpdate(settings.fetchDepth, settings.nestedSubmodules)
await git.submoduleForeach(
'git config --local gc.auto 0',
settings.nestedSubmodules
)
core.endGroup()
// Persist credentials
if (settings.persistCredentials) {
core.startGroup('Persisting credentials for submodules')
await authHelper.configureSubmoduleAuth()
core.endGroup()
}
} finally {
// Remove temporary global config override
await authHelper.removeGlobalAuth()
// Persist credentials
if (settings.persistCredentials) {
core.startGroup('Persisting credentials for submodules')
await authHelper.configureSubmoduleAuth()
core.endGroup()
}
}
// Dump some info about the checked out commit
// Get commit information
const commitInfo = await git.log1()
// Log commit sha
const commitSHA = await git.log1('--format=%H')
core.setOutput('commit', commitSHA.trim())
// Check for incorrect pull request merge commit
await refHelper.checkCommitInfo(
settings.authToken,
@ -196,14 +271,18 @@ export async function getSource(settings: IGitSourceSettings): Promise<void> {
settings.repositoryOwner,
settings.repositoryName,
settings.ref,
settings.commit
settings.commit,
settings.githubServerUrl
)
} finally {
// Remove auth
if (!settings.persistCredentials) {
core.startGroup('Removing auth')
await authHelper.removeAuth()
core.endGroup()
if (authHelper) {
if (!settings.persistCredentials) {
core.startGroup('Removing auth')
await authHelper.removeAuth()
core.endGroup()
}
authHelper.removeGlobalConfig()
}
}
}
@ -219,14 +298,37 @@ export async function cleanup(repositoryPath: string): Promise<void> {
let git: IGitCommandManager
try {
git = await gitCommandManager.createCommandManager(repositoryPath, false)
git = await gitCommandManager.createCommandManager(
repositoryPath,
false,
false
)
} catch {
return
}
// Remove auth
const authHelper = gitAuthHelper.createAuthHelper(git)
await authHelper.removeAuth()
try {
if (stateHelper.PostSetSafeDirectory) {
// Setup the repository path as a safe directory, so if we pass this into a container job with a different user it doesn't fail
// Otherwise all git commands we run in a container fail
await authHelper.configureTempGlobalConfig()
core.info(
`Adding repository directory to the temporary git global config as a safe directory`
)
await git
.config('safe.directory', repositoryPath, true, true)
.catch(error => {
core.info(`Failed to initialize safe directory with error: ${error}`)
})
}
await authHelper.removeAuth()
} finally {
await authHelper.removeGlobalConfig()
}
}
async function getGitCommandManager(
@ -236,7 +338,8 @@ async function getGitCommandManager(
try {
return await gitCommandManager.createCommandManager(
settings.repositoryPath,
settings.lfs
settings.lfs,
settings.sparseCheckout != null
)
} catch (err) {
// Git is required for LFS

View File

@ -29,11 +29,36 @@ export interface IGitSourceSettings {
*/
clean: boolean
/**
* The filter determining which objects to include
*/
filter: string | undefined
/**
* The array of folders to make the sparse checkout
*/
sparseCheckout: string[]
/**
* Indicates whether to use cone mode in the sparse checkout (if any)
*/
sparseCheckoutConeMode: boolean
/**
* The depth when fetching
*/
fetchDepth: number
/**
* Fetch tags, even if fetchDepth > 0 (default: false)
*/
fetchTags: boolean
/**
* Indicates whether to use the --progress option when fetching
*/
showProgress: boolean
/**
* Indicates whether to fetch LFS objects
*/
@ -69,8 +94,28 @@ export interface IGitSourceSettings {
*/
sshStrict: boolean
/**
* The SSH user to login as
*/
sshUser: string
/**
* Indicates whether to persist the credentials on disk to enable scripting authenticated git commands
*/
persistCredentials: boolean
/**
* Organization ID for the currently running workflow (used for auth settings)
*/
workflowOrganizationId: number | undefined
/**
* Indicates whether to add repositoryPath as safe.directory in git global config
*/
setSafeDirectory: boolean
/**
* User override on the GitHub Server/Host URL that hosts the repository to be cloned
*/
githubServerUrl: string | undefined
}

View File

@ -6,8 +6,8 @@ import * as io from '@actions/io'
import * as path from 'path'
import * as retryHelper from './retry-helper'
import * as toolCache from '@actions/tool-cache'
import {default as uuid} from 'uuid/v4'
import {Octokit} from '@octokit/rest'
import {v4 as uuid} from 'uuid'
import {getServerApiUrl} from './url-helper'
const IS_WINDOWS = process.platform === 'win32'
@ -17,18 +17,27 @@ export async function downloadRepository(
repo: string,
ref: string,
commit: string,
repositoryPath: string
repositoryPath: string,
baseUrl?: string
): Promise<void> {
// Determine the default branch
if (!ref && !commit) {
core.info('Determining the default branch')
ref = await getDefaultBranch(authToken, owner, repo, baseUrl)
}
// Download the archive
let archiveData = await retryHelper.execute(async () => {
core.info('Downloading the archive')
return await downloadArchive(authToken, owner, repo, ref, commit)
return await downloadArchive(authToken, owner, repo, ref, commit, baseUrl)
})
// Write archive to disk
core.info('Writing archive to disk')
const uniqueId = uuid()
const archivePath = path.join(repositoryPath, `${uniqueId}.tar.gz`)
const archivePath = IS_WINDOWS
? path.join(repositoryPath, `${uniqueId}.zip`)
: path.join(repositoryPath, `${uniqueId}.tar.gz`)
await fs.promises.writeFile(archivePath, archiveData)
archiveData = Buffer.from('') // Free memory
@ -41,7 +50,7 @@ export async function downloadRepository(
} else {
await toolCache.extractTar(archivePath, extractPath)
}
io.rmRF(archivePath)
await io.rmRF(archivePath)
// Determine the path of the repository content. The archive contains
// a top-level folder and the repository content is inside.
@ -64,7 +73,53 @@ export async function downloadRepository(
await io.mv(sourcePath, targetPath)
}
}
io.rmRF(extractPath)
await io.rmRF(extractPath)
}
/**
* Looks up the default branch name
*/
export async function getDefaultBranch(
authToken: string,
owner: string,
repo: string,
baseUrl?: string
): Promise<string> {
return await retryHelper.execute(async () => {
core.info('Retrieving the default branch name')
const octokit = github.getOctokit(authToken, {
baseUrl: getServerApiUrl(baseUrl)
})
let result: string
try {
// Get the default branch from the repo info
const response = await octokit.rest.repos.get({owner, repo})
result = response.data.default_branch
assert.ok(result, 'default_branch cannot be empty')
} catch (err) {
// Handle .wiki repo
if (
(err as any)?.status === 404 &&
repo.toUpperCase().endsWith('.WIKI')
) {
result = 'master'
}
// Otherwise error
else {
throw err
}
}
// Print the default branch
core.info(`Default branch '${result}'`)
// Prefix with 'refs/heads'
if (!result.startsWith('refs/')) {
result = `refs/heads/${result}`
}
return result
})
}
async function downloadArchive(
@ -72,21 +127,19 @@ async function downloadArchive(
owner: string,
repo: string,
ref: string,
commit: string
commit: string,
baseUrl?: string
): Promise<Buffer> {
const octokit = new github.GitHub(authToken)
const params: Octokit.ReposGetArchiveLinkParams = {
const octokit = github.getOctokit(authToken, {
baseUrl: getServerApiUrl(baseUrl)
})
const download = IS_WINDOWS
? octokit.rest.repos.downloadZipballArchive
: octokit.rest.repos.downloadTarballArchive
const response = await download({
owner: owner,
repo: repo,
archive_format: IS_WINDOWS ? 'zipball' : 'tarball',
ref: commit || ref
}
const response = await octokit.repos.getArchiveLink(params)
if (response.status != 200) {
throw new Error(
`Unexpected response from GitHub API. Status: ${response.status}, Data: ${response.data}`
)
}
return Buffer.from(response.data) // response.data is ArrayBuffer
})
return Buffer.from(response.data as ArrayBuffer) // response.data is ArrayBuffer
}

View File

@ -2,10 +2,11 @@ import * as core from '@actions/core'
import * as fsHelper from './fs-helper'
import * as github from '@actions/github'
import * as path from 'path'
import * as workflowContextHelper from './workflow-context-helper'
import {IGitSourceSettings} from './git-source-settings'
export function getInputs(): IGitSourceSettings {
const result = ({} as unknown) as IGitSourceSettings
export async function getInputs(): Promise<IGitSourceSettings> {
const result = {} as unknown as IGitSourceSettings
// GitHub workspace
let githubWorkspacePath = process.env['GITHUB_WORKSPACE']
@ -63,15 +64,11 @@ export function getInputs(): IGitSourceSettings {
result.commit = github.context.sha
// Some events have an unqualifed ref. For example when a PR is merged (pull_request closed event),
// the ref is unqualifed like "master" instead of "refs/heads/master".
// the ref is unqualifed like "main" instead of "refs/heads/main".
if (result.commit && result.ref && !result.ref.startsWith('refs/')) {
result.ref = `refs/heads/${result.ref}`
}
}
if (!result.ref && !result.commit) {
result.ref = 'refs/heads/master'
}
}
// SHA?
else if (result.ref.match(/^[0-9a-fA-F]{40}$/)) {
@ -85,6 +82,25 @@ export function getInputs(): IGitSourceSettings {
result.clean = (core.getInput('clean') || 'true').toUpperCase() === 'TRUE'
core.debug(`clean = ${result.clean}`)
// Filter
const filter = core.getInput('filter')
if (filter) {
result.filter = filter
}
core.debug(`filter = ${result.filter}`)
// Sparse checkout
const sparseCheckout = core.getMultilineInput('sparse-checkout')
if (sparseCheckout.length) {
result.sparseCheckout = sparseCheckout
core.debug(`sparse checkout = ${result.sparseCheckout}`)
}
result.sparseCheckoutConeMode =
(core.getInput('sparse-checkout-cone-mode') || 'true').toUpperCase() ===
'TRUE'
// Fetch depth
result.fetchDepth = Math.floor(Number(core.getInput('fetch-depth') || '1'))
if (isNaN(result.fetchDepth) || result.fetchDepth < 0) {
@ -92,6 +108,16 @@ export function getInputs(): IGitSourceSettings {
}
core.debug(`fetch depth = ${result.fetchDepth}`)
// Fetch tags
result.fetchTags =
(core.getInput('fetch-tags') || 'false').toUpperCase() === 'TRUE'
core.debug(`fetch tags = ${result.fetchTags}`)
// Show fetch progress
result.showProgress =
(core.getInput('show-progress') || 'true').toUpperCase() === 'TRUE'
core.debug(`show progress = ${result.showProgress}`)
// LFS
result.lfs = (core.getInput('lfs') || 'false').toUpperCase() === 'TRUE'
core.debug(`lfs = ${result.lfs}`)
@ -110,17 +136,30 @@ export function getInputs(): IGitSourceSettings {
core.debug(`recursive submodules = ${result.nestedSubmodules}`)
// Auth token
result.authToken = core.getInput('token')
result.authToken = core.getInput('token', {required: true})
// SSH
result.sshKey = core.getInput('ssh-key')
result.sshKnownHosts = core.getInput('ssh-known-hosts')
result.sshStrict =
(core.getInput('ssh-strict') || 'true').toUpperCase() === 'TRUE'
result.sshUser = core.getInput('ssh-user')
// Persist credentials
result.persistCredentials =
(core.getInput('persist-credentials') || 'false').toUpperCase() === 'TRUE'
// Workflow organization ID
result.workflowOrganizationId =
await workflowContextHelper.getOrganizationId()
// Set safe.directory in git global config.
result.setSafeDirectory =
(core.getInput('set-safe-directory') || 'true').toUpperCase() === 'TRUE'
// Determine the GitHub URL that the repository is being hosted from
result.githubServerUrl = core.getInput('github-server-url')
core.debug(`GitHub Host URL = ${result.githubServerUrl}`)
return result
}

View File

@ -7,7 +7,7 @@ import * as stateHelper from './state-helper'
async function run(): Promise<void> {
try {
const sourceSettings = inputHelper.getInputs()
const sourceSettings = await inputHelper.getInputs()
try {
// Register problem matcher
@ -19,12 +19,13 @@ async function run(): Promise<void> {
// Get sources
await gitSourceProvider.getSource(sourceSettings)
core.setOutput('ref', sourceSettings.ref)
} finally {
// Unregister problem matcher
coreCommand.issueCommand('remove-matcher', {owner: 'checkout-git'}, '')
}
} catch (error) {
core.setFailed(error.message)
core.setFailed(`${(error as any)?.message ?? error}`)
}
}
@ -32,7 +33,7 @@ async function cleanup(): Promise<void> {
try {
await gitSourceProvider.cleanup(stateHelper.RepositoryPath)
} catch (error) {
core.warning(error.message)
core.warning(`${(error as any)?.message ?? error}`)
}
}

View File

@ -10,17 +10,17 @@ import * as yaml from 'js-yaml'
function updateUsage(
actionReference: string,
actionYamlPath: string = 'action.yml',
readmePath: string = 'README.md',
startToken: string = '<!-- start usage -->',
endToken: string = '<!-- end usage -->'
actionYamlPath = 'action.yml',
readmePath = 'README.md',
startToken = '<!-- start usage -->',
endToken = '<!-- end usage -->'
): void {
if (!actionReference) {
throw new Error('Parameter actionReference must not be empty')
}
// Load the action.yml
const actionYaml = yaml.safeLoad(fs.readFileSync(actionYamlPath).toString())
const actionYaml = yaml.load(fs.readFileSync(actionYamlPath).toString())
// Load the README
const originalReadme = fs.readFileSync(readmePath).toString()
@ -120,7 +120,7 @@ function updateUsage(
}
updateUsage(
'actions/checkout@v2',
'actions/checkout@v4',
path.join(__dirname, '..', '..', 'action.yml'),
path.join(__dirname, '..', '..', 'README.md')
)

8
src/misc/licensed-check.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
src/misc/licensed-download.sh
echo 'Running: licensed cached'
_temp/licensed-3.6.0/licensed status

24
src/misc/licensed-download.sh Executable file
View File

@ -0,0 +1,24 @@
#!/bin/bash
set -e
if [ ! -f _temp/licensed-3.6.0.done ]; then
echo 'Clearing temp'
rm -rf _temp/licensed-3.6.0 || true
echo 'Downloading licensed'
mkdir -p _temp/licensed-3.6.0
pushd _temp/licensed-3.6.0
if [[ "$OSTYPE" == "darwin"* ]]; then
curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.6.0/licensed-3.6.0-darwin-x64.tar.gz
else
curl -Lfs -o licensed.tar.gz https://github.com/github/licensed/releases/download/3.6.0/licensed-3.6.0-linux-x64.tar.gz
fi
echo 'Extracting licenesed'
tar -xzf licensed.tar.gz
popd
touch _temp/licensed-3.6.0.done
else
echo 'Licensed already downloaded'
fi

8
src/misc/licensed-generate.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
src/misc/licensed-download.sh
echo 'Running: licensed cached'
_temp/licensed-3.6.0/licensed cache

View File

@ -1,7 +1,7 @@
import {URL} from 'url'
import {IGitCommandManager} from './git-command-manager'
import * as core from '@actions/core'
import * as github from '@actions/github'
import {getServerApiUrl, isGhes} from './url-helper'
export const tagsRefSpec = '+refs/tags/*:refs/tags/*'
@ -23,7 +23,7 @@ export async function getCheckoutInfo(
throw new Error('Args ref and commit cannot both be empty')
}
const result = ({} as unknown) as ICheckoutInfo
const result = {} as unknown as ICheckoutInfo
const upperRef = (ref || '').toUpperCase()
// SHA only
@ -42,9 +42,13 @@ export async function getCheckoutInfo(
result.ref = `refs/remotes/pull/${branch}`
}
// refs/tags/
else if (upperRef.startsWith('REFS/')) {
else if (upperRef.startsWith('REFS/TAGS/')) {
result.ref = ref
}
// refs/
else if (upperRef.startsWith('REFS/')) {
result.ref = commit ? commit : ref
}
// Unqualified ref, check for a matching branch or tag
else {
if (await git.branchExists(true, `origin/${ref}`)) {
@ -183,11 +187,12 @@ export async function checkCommitInfo(
repositoryOwner: string,
repositoryName: string,
ref: string,
commit: string
commit: string,
baseUrl?: string
): Promise<void> {
try {
// GHES?
if (isGhes()) {
if (isGhes(baseUrl)) {
return
}
@ -243,17 +248,23 @@ export async function checkCommitInfo(
core.debug(
`Expected head sha ${expectedHeadSha}; actual head sha ${actualHeadSha}`
)
const octokit = new github.GitHub(token, {
const octokit = github.getOctokit(token, {
baseUrl: getServerApiUrl(baseUrl),
userAgent: `actions-checkout-tracepoint/1.0 (code=STALE_MERGE;owner=${repositoryOwner};repo=${repositoryName};pr=${fromPayload(
'number'
)};run_id=${
process.env['GITHUB_RUN_ID']
};expected_head_sha=${expectedHeadSha};actual_head_sha=${actualHeadSha})`
})
await octokit.repos.get({owner: repositoryOwner, repo: repositoryName})
await octokit.rest.repos.get({
owner: repositoryOwner,
repo: repositoryName
})
}
} catch (err) {
core.debug(`Error when validating commit info: ${err.stack}`)
core.debug(
`Error when validating commit info: ${(err as any)?.stack ?? err}`
)
}
}
@ -274,10 +285,3 @@ function select(obj: any, path: string): any {
const key = path.substr(0, i)
return select(obj[key], path.substr(i + 1))
}
function isGhes(): boolean {
const ghUrl = new URL(
process.env['GITHUB_SERVER_URL'] || 'https://github.com'
)
return ghUrl.hostname.toUpperCase() !== 'GITHUB.COM'
}

View File

@ -29,7 +29,7 @@ export class RetryHelper {
try {
return await action()
} catch (err) {
core.info(err.message)
core.info((err as any)?.message)
}
// Sleep

View File

@ -1,58 +1,60 @@
import * as coreCommand from '@actions/core/lib/command'
import * as core from '@actions/core'
/**
* Indicates whether the POST action is running
*/
export const IsPost = !!process.env['STATE_isPost']
export const IsPost = !!core.getState('isPost')
/**
* The repository path for the POST action. The value is empty during the MAIN action.
*/
export const RepositoryPath =
(process.env['STATE_repositoryPath'] as string) || ''
export const RepositoryPath = core.getState('repositoryPath')
/**
* The set-safe-directory for the POST action. The value is set if input: 'safe-directory' is set during the MAIN action.
*/
export const PostSetSafeDirectory = core.getState('setSafeDirectory') === 'true'
/**
* The SSH key path for the POST action. The value is empty during the MAIN action.
*/
export const SshKeyPath = (process.env['STATE_sshKeyPath'] as string) || ''
export const SshKeyPath = core.getState('sshKeyPath')
/**
* The SSH known hosts path for the POST action. The value is empty during the MAIN action.
*/
export const SshKnownHostsPath =
(process.env['STATE_sshKnownHostsPath'] as string) || ''
export const SshKnownHostsPath = core.getState('sshKnownHostsPath')
/**
* Save the repository path so the POST action can retrieve the value.
*/
export function setRepositoryPath(repositoryPath: string) {
coreCommand.issueCommand(
'save-state',
{name: 'repositoryPath'},
repositoryPath
)
core.saveState('repositoryPath', repositoryPath)
}
/**
* Save the SSH key path so the POST action can retrieve the value.
*/
export function setSshKeyPath(sshKeyPath: string) {
coreCommand.issueCommand('save-state', {name: 'sshKeyPath'}, sshKeyPath)
core.saveState('sshKeyPath', sshKeyPath)
}
/**
* Save the SSH known hosts path so the POST action can retrieve the value.
*/
export function setSshKnownHostsPath(sshKnownHostsPath: string) {
coreCommand.issueCommand(
'save-state',
{name: 'sshKnownHostsPath'},
sshKnownHostsPath
)
core.saveState('sshKnownHostsPath', sshKnownHostsPath)
}
/**
* Save the set-safe-directory input so the POST action can retrieve the value.
*/
export function setSafeDirectory() {
core.saveState('setSafeDirectory', 'true')
}
// Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic.
// This is necessary since we don't have a separate entry point.
if (!IsPost) {
coreCommand.issueCommand('save-state', {name: 'isPost'}, 'true')
core.saveState('isPost', 'true')
}

View File

@ -1,6 +1,6 @@
import * as assert from 'assert'
import {IGitSourceSettings} from './git-source-settings'
import {URL} from 'url'
import {IGitSourceSettings} from './git-source-settings'
export function getFetchUrl(settings: IGitSourceSettings): string {
assert.ok(
@ -8,22 +8,74 @@ export function getFetchUrl(settings: IGitSourceSettings): string {
'settings.repositoryOwner must be defined'
)
assert.ok(settings.repositoryName, 'settings.repositoryName must be defined')
const serviceUrl = getServerUrl()
const serviceUrl = getServerUrl(settings.githubServerUrl)
const encodedOwner = encodeURIComponent(settings.repositoryOwner)
const encodedName = encodeURIComponent(settings.repositoryName)
if (settings.sshKey) {
return `git@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`
const user = settings.sshUser.length > 0 ? settings.sshUser : 'git'
return `${user}@${serviceUrl.hostname}:${encodedOwner}/${encodedName}.git`
}
// "origin" is SCHEME://HOSTNAME[:PORT]
return `${serviceUrl.origin}/${encodedOwner}/${encodedName}`
}
export function getServerUrl(): URL {
// todo: remove GITHUB_URL after support for GHES Alpha is no longer needed
return new URL(
process.env['GITHUB_SERVER_URL'] ||
process.env['GITHUB_URL'] ||
'https://github.com'
)
export function getServerUrl(url?: string): URL {
let resolvedUrl = process.env['GITHUB_SERVER_URL'] || 'https://github.com'
if (hasContent(url, WhitespaceMode.Trim)) {
resolvedUrl = url!
}
return new URL(resolvedUrl)
}
export function getServerApiUrl(url?: string): string {
if (hasContent(url, WhitespaceMode.Trim)) {
let serverUrl = getServerUrl(url)
if (isGhes(url)) {
serverUrl.pathname = 'api/v3'
} else {
serverUrl.hostname = 'api.' + serverUrl.hostname
}
return pruneSuffix(serverUrl.toString(), '/')
}
return process.env['GITHUB_API_URL'] || 'https://api.github.com'
}
export function isGhes(url?: string): boolean {
const ghUrl = new URL(
url || process.env['GITHUB_SERVER_URL'] || 'https://github.com'
)
const hostname = ghUrl.hostname.trimEnd().toUpperCase()
const isGitHubHost = hostname === 'GITHUB.COM'
const isGitHubEnterpriseCloudHost = hostname.endsWith('.GHE.COM')
const isLocalHost = hostname.endsWith('.LOCALHOST')
return !isGitHubHost && !isGitHubEnterpriseCloudHost && !isLocalHost
}
function pruneSuffix(text: string, suffix: string) {
if (hasContent(suffix, WhitespaceMode.Preserve) && text?.endsWith(suffix)) {
return text.substring(0, text.length - suffix.length)
}
return text
}
enum WhitespaceMode {
Trim,
Preserve
}
function hasContent(
text: string | undefined,
whitespaceMode: WhitespaceMode
): boolean {
let refinedText = text ?? ''
if (whitespaceMode == WhitespaceMode.Trim) {
refinedText = refinedText.trim()
}
return refinedText.length > 0
}

View File

@ -0,0 +1,31 @@
import * as core from '@actions/core'
import * as fs from 'fs'
/**
* Gets the organization ID of the running workflow or undefined if the value cannot be loaded from the GITHUB_EVENT_PATH
*/
export async function getOrganizationId(): Promise<number | undefined> {
try {
const eventPath = process.env.GITHUB_EVENT_PATH
if (!eventPath) {
core.debug(`GITHUB_EVENT_PATH is not defined`)
return
}
const content = await fs.promises.readFile(eventPath, {encoding: 'utf8'})
const event = JSON.parse(content)
const id = event?.repository?.owner?.id
if (typeof id !== 'number') {
core.debug('Repository owner ID not found within GITHUB event info')
return
}
return id as number
} catch (err) {
core.debug(
`Unable to load organization ID from GITHUB_EVENT_PATH: ${
(err as any).message || err
}`
)
}
}

View File

@ -10,7 +10,8 @@
"declaration": true,
"strict": true,
"noImplicitAny": false,
"esModuleInterop": true
"esModuleInterop": true,
"skipLibCheck": true
},
"exclude": ["__test__", "lib", "node_modules"]
}