diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml new file mode 100644 index 0000000..095592a --- /dev/null +++ b/.github/workflows/e2e-tests.yml @@ -0,0 +1,160 @@ +name: E2E Tests + +on: + # For local testing with: act push -W .github/workflows/e2e-tests.yml + push: + branches-ignore: + - "**" # Never runs on GitHub, only locally with act + + # For test.yml to call this workflow + workflow_call: + secrets: + OP_CONNECT_CREDENTIALS: + required: true + OP_CONNECT_TOKEN: + required: true + OP_SERVICE_ACCOUNT_TOKEN: + required: true + VAULT: + description: "1Password vault name or UUID" + required: true + +jobs: + test-service-account: + name: Service Account (${{ matrix.os }}, ${{ matrix.version }}, export-env=${{ matrix.export-env }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + version: [latest, 2.30.0] + export-env: [true, false] + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Generate .env.tpl + shell: bash + run: | + echo "FILE_SECRET=op://${{ secrets.VAULT }}/test-secret/password" > tests/.env.tpl + echo "FILE_SECRET_IN_SECTION=op://${{ secrets.VAULT }}/test-secret/test-section/password" >> tests/.env.tpl + echo "FILE_MULTILINE_SECRET=op://${{ secrets.VAULT }}/multiline-secret/notesPlain" >> tests/.env.tpl + + - name: Configure Service account + uses: ./configure + with: + service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} + + - name: Load secrets + id: load_secrets + uses: ./ + with: + version: ${{ matrix.version }} + export-env: ${{ matrix.export-env }} + env: + SECRET: op://${{ secrets.VAULT }}/test-secret/password + SECRET_IN_SECTION: op://${{ secrets.VAULT }}/test-secret/test-section/password + MULTILINE_SECRET: op://${{ secrets.VAULT }}/multiline-secret/notesPlain + OP_ENV_FILE: ./tests/.env.tpl + + - name: Assert test secret values [step output] + if: ${{ !matrix.export-env }} + shell: bash + env: + SECRET: ${{ steps.load_secrets.outputs.SECRET }} + SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.SECRET_IN_SECTION }} + MULTILINE_SECRET: ${{ steps.load_secrets.outputs.MULTILINE_SECRET }} + FILE_SECRET: ${{ steps.load_secrets.outputs.FILE_SECRET }} + FILE_SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.FILE_SECRET_IN_SECTION }} + FILE_MULTILINE_SECRET: ${{ steps.load_secrets.outputs.FILE_MULTILINE_SECRET }} + run: ./tests/assert-env-set.sh + + - name: Assert test secret values [exported env] + if: ${{ matrix.export-env }} + shell: bash + run: ./tests/assert-env-set.sh + + - name: Remove secrets [exported env] + if: ${{ matrix.export-env }} + uses: ./ + with: + unset-previous: true + + - name: Assert removed secrets [exported env] + if: ${{ matrix.export-env }} + shell: bash + run: ./tests/assert-env-unset.sh + + test-connect: + name: Connect (ubuntu-latest, ${{ matrix.version }}, export-env=${{ matrix.export-env }}) + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + version: [latest, 2.30.0] + export-env: [true, false] + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Generate .env.tpl + run: | + mkdir -p tests + echo "FILE_SECRET=op://${{ secrets.VAULT }}/test-secret/password" > tests/.env.tpl + echo "FILE_SECRET_IN_SECTION=op://${{ secrets.VAULT }}/test-secret/test-section/password" >> tests/.env.tpl + echo "FILE_MULTILINE_SECRET=op://${{ secrets.VAULT }}/multiline-secret/notesPlain" >> tests/.env.tpl + + - name: Launch 1Password Connect instance + env: + OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }} + run: | + echo "$OP_CONNECT_CREDENTIALS" > 1password-credentials.json + docker compose -f tests/fixtures/docker-compose.yml up -d && sleep 10 + + - name: Configure 1Password Connect + uses: ./configure + with: + connect-host: http://localhost:8080 + connect-token: ${{ secrets.OP_CONNECT_TOKEN }} + + - name: Load secrets + id: load_secrets + uses: ./ + with: + version: ${{ matrix.version }} + export-env: ${{ matrix.export-env }} + env: + SECRET: op://${{ secrets.VAULT }}/test-secret/password + SECRET_IN_SECTION: op://${{ secrets.VAULT }}/test-secret/test-section/password + MULTILINE_SECRET: op://${{ secrets.VAULT }}/multiline-secret/notesPlain + OP_ENV_FILE: ./tests/.env.tpl + + - name: Assert test secret values [step output] + if: ${{ !matrix.export-env }} + env: + SECRET: ${{ steps.load_secrets.outputs.SECRET }} + SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.SECRET_IN_SECTION }} + MULTILINE_SECRET: ${{ steps.load_secrets.outputs.MULTILINE_SECRET }} + FILE_SECRET: ${{ steps.load_secrets.outputs.FILE_SECRET }} + FILE_SECRET_IN_SECTION: ${{ steps.load_secrets.outputs.FILE_SECRET_IN_SECTION }} + FILE_MULTILINE_SECRET: ${{ steps.load_secrets.outputs.FILE_MULTILINE_SECRET }} + run: ./tests/assert-env-set.sh + + - name: Assert test secret values [exported env] + if: ${{ matrix.export-env }} + run: ./tests/assert-env-set.sh + + - name: Remove secrets [exported env] + if: ${{ matrix.export-env }} + uses: ./ + with: + unset-previous: true + + - name: Assert removed secrets [exported env] + if: ${{ matrix.export-env }} + run: ./tests/assert-env-unset.sh diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml new file mode 100644 index 0000000..e0ff6e8 --- /dev/null +++ b/.github/workflows/lint-and-test.yml @@ -0,0 +1,36 @@ +name: Lint and Test + +on: + push: + branches: [main] + pull_request: + +jobs: + lint-and-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 + with: + ignore_paths: >- + .husky + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Check formatting + run: npm run format:check + + - name: Check lint + run: npm run lint + + - name: Run unit tests + run: npm test diff --git a/.github/workflows/ok-to-test.yml b/.github/workflows/ok-to-test.yml index e1d4060..cb1c547 100644 --- a/.github/workflows/ok-to-test.yml +++ b/.github/workflows/ok-to-test.yml @@ -1,4 +1,4 @@ -# If someone with write access comments "/ok-to-test" on a pull request, emit a repository_dispatch event +# Write comments "/ok-to-test sha=" on a pull request. This will emit a repository_dispatch event. name: Ok To Test on: @@ -15,7 +15,7 @@ jobs: if: ${{ github.event.issue.pull_request }} steps: - name: Slash Command Dispatch - uses: peter-evans/slash-command-dispatch@v3 + uses: peter-evans/slash-command-dispatch@v5 with: token: ${{ secrets.GITHUB_TOKEN }} reaction-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml new file mode 100644 index 0000000..9b2b360 --- /dev/null +++ b/.github/workflows/test-e2e.yml @@ -0,0 +1,114 @@ +name: E2E Tests + +on: + push: + branches: [main] + paths-ignore: &ignore_paths + - "docs/**" + - "config/**" + - "*.md" + - ".gitignore" + - "LICENSE" + pull_request: + paths-ignore: *ignore_paths + repository_dispatch: + types: [ok-to-test-command] + +concurrency: + group: >- + ${{ github.event_name == 'pull_request' && + format('e2e-{0}', github.event.pull_request.head.ref) || + format('e2e-{0}', github.ref) }} + cancel-in-progress: true + +jobs: + check-external-pr: + runs-on: ubuntu-latest + outputs: + condition: ${{ steps.check.outputs.condition }} + steps: + - name: Check if PR is from external contributor + id: check + run: | + echo "Event name: ${{ github.event_name }}" + echo "Repository: ${{ github.repository }}" + + if [ "${{ github.event_name }}" == "pull_request" ]; then + # For pull_request events, check if PR is from external fork + echo "PR head repo: ${{ github.event.pull_request.head.repo.full_name }}" + if [ "${{ github.actor }}" == "dependabot[bot]" ]; then + echo "condition=skip" >> $GITHUB_OUTPUT + echo "Setting condition=skip (Dependabot PR)" + elif [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then + echo "condition=skip" >> $GITHUB_OUTPUT + echo "Setting condition=skip (external fork PR creation)" + else + echo "condition=pr-creation-maintainer" >> $GITHUB_OUTPUT + echo "Setting condition=pr-creation-maintainer (internal PR creation)" + fi + elif [ "${{ github.event_name }}" == "repository_dispatch" ]; then + # For repository_dispatch events (ok-to-test), check if sha matches + SHA_PARAM="${{ github.event.client_payload.slash_command.args.named.sha }}" + PR_HEAD_SHA="${{ github.event.client_payload.pull_request.head.sha }}" + + echo "Checking dispatch event conditions..." + echo "SHA from command: $SHA_PARAM" + echo "PR head SHA: $PR_HEAD_SHA" + + if [ -n "$SHA_PARAM" ] && [[ "$PR_HEAD_SHA" == *"$SHA_PARAM"* ]]; then + echo "condition=dispatch-event" >> $GITHUB_OUTPUT + echo "Setting condition=dispatch-event (sha matches)" + else + echo "condition=skip" >> $GITHUB_OUTPUT + echo "Setting condition=skip (sha does not match or empty)" + fi + elif [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref_name }}" == "main" ]; then + echo "condition=push-to-main" >> $GITHUB_OUTPUT + echo "Setting condition=push-to-main (push to main)" + else + # Unknown event type + echo "condition=skip" >> $GITHUB_OUTPUT + echo "Setting condition=skip (unknown event type: ${{ github.event_name }})" + fi + + e2e: + needs: check-external-pr + if: | + (needs.check-external-pr.outputs.condition == 'pr-creation-maintainer') + || + (needs.check-external-pr.outputs.condition == 'dispatch-event') + || + needs.check-external-pr.outputs.condition == 'push-to-main' + uses: ./.github/workflows/e2e-tests.yml + secrets: + OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }} + OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }} + OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} + VAULT: ${{ secrets.VAULT }} + + # Post comment on fork PRs after /ok-to-test + comment-pr: + needs: [check-external-pr, e2e] + runs-on: ubuntu-latest + if: always() && needs.check-external-pr.outputs.condition == 'dispatch-event' + permissions: + pull-requests: write + steps: + - name: Create URL to the run output + id: vars + run: echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT + + - name: Create comment on PR + uses: peter-evans/create-or-update-comment@v5 + with: + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + ${{ + needs.e2e.result == 'success' && '✅ E2E tests passed.' || + needs.e2e.result == 'failure' && '❌ E2E tests failed.' || + '⚠️ E2E tests completed.' + }} + + [View test run output][1] + + [1]: ${{ steps.vars.outputs.run-url }} diff --git a/.gitignore b/.gitignore index b509c88..5b89572 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ coverage/ node_modules/ +.idea/ +1password-credentials.json diff --git a/dist/index.js b/dist/index.js index eb2fc10..9444841 100644 --- a/dist/index.js +++ b/dist/index.js @@ -6350,2702 +6350,6 @@ function lookpath(command, opt) { exports.lookpath = lookpath; -/***/ }), - -/***/ 6688: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const ANY = Symbol('SemVer ANY') -// hoisted class for cyclic dependency -class Comparator { - static get ANY () { - return ANY - } - - constructor (comp, options) { - options = parseOptions(options) - - if (comp instanceof Comparator) { - if (comp.loose === !!options.loose) { - return comp - } else { - comp = comp.value - } - } - - comp = comp.trim().split(/\s+/).join(' ') - debug('comparator', comp, options) - this.options = options - this.loose = !!options.loose - this.parse(comp) - - if (this.semver === ANY) { - this.value = '' - } else { - this.value = this.operator + this.semver.version - } - - debug('comp', this) - } - - parse (comp) { - const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR] - const m = comp.match(r) - - if (!m) { - throw new TypeError(`Invalid comparator: ${comp}`) - } - - this.operator = m[1] !== undefined ? m[1] : '' - if (this.operator === '=') { - this.operator = '' - } - - // if it literally is just '>' or '' then allow anything. - if (!m[2]) { - this.semver = ANY - } else { - this.semver = new SemVer(m[2], this.options.loose) - } - } - - toString () { - return this.value - } - - test (version) { - debug('Comparator.test', version, this.options.loose) - - if (this.semver === ANY || version === ANY) { - return true - } - - if (typeof version === 'string') { - try { - version = new SemVer(version, this.options) - } catch (er) { - return false - } - } - - return cmp(version, this.operator, this.semver, this.options) - } - - intersects (comp, options) { - if (!(comp instanceof Comparator)) { - throw new TypeError('a Comparator is required') - } - - if (this.operator === '') { - if (this.value === '') { - return true - } - return new Range(comp.value, options).test(this.value) - } else if (comp.operator === '') { - if (comp.value === '') { - return true - } - return new Range(this.value, options).test(comp.semver) - } - - options = parseOptions(options) - - // Special cases where nothing can possibly be lower - if (options.includePrerelease && - (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) { - return false - } - if (!options.includePrerelease && - (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) { - return false - } - - // Same direction increasing (> or >=) - if (this.operator.startsWith('>') && comp.operator.startsWith('>')) { - return true - } - // Same direction decreasing (< or <=) - if (this.operator.startsWith('<') && comp.operator.startsWith('<')) { - return true - } - // same SemVer and both sides are inclusive (<= or >=) - if ( - (this.semver.version === comp.semver.version) && - this.operator.includes('=') && comp.operator.includes('=')) { - return true - } - // opposite directions less than - if (cmp(this.semver, '<', comp.semver, options) && - this.operator.startsWith('>') && comp.operator.startsWith('<')) { - return true - } - // opposite directions greater than - if (cmp(this.semver, '>', comp.semver, options) && - this.operator.startsWith('<') && comp.operator.startsWith('>')) { - return true - } - return false - } -} - -module.exports = Comparator - -const parseOptions = __nccwpck_require__(5547) -const { safeRe: re, t } = __nccwpck_require__(4326) -const cmp = __nccwpck_require__(3663) -const debug = __nccwpck_require__(9576) -const SemVer = __nccwpck_require__(6868) -const Range = __nccwpck_require__(3892) - - -/***/ }), - -/***/ 3892: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SPACE_CHARACTERS = /\s+/g - -// hoisted class for cyclic dependency -class Range { - constructor (range, options) { - options = parseOptions(options) - - if (range instanceof Range) { - if ( - range.loose === !!options.loose && - range.includePrerelease === !!options.includePrerelease - ) { - return range - } else { - return new Range(range.raw, options) - } - } - - if (range instanceof Comparator) { - // just put it in the set and return - this.raw = range.value - this.set = [[range]] - this.formatted = undefined - return this - } - - this.options = options - this.loose = !!options.loose - this.includePrerelease = !!options.includePrerelease - - // First reduce all whitespace as much as possible so we do not have to rely - // on potentially slow regexes like \s*. This is then stored and used for - // future error messages as well. - this.raw = range.trim().replace(SPACE_CHARACTERS, ' ') - - // First, split on || - this.set = this.raw - .split('||') - // map the range to a 2d array of comparators - .map(r => this.parseRange(r.trim())) - // throw out any comparator lists that are empty - // this generally means that it was not a valid range, which is allowed - // in loose mode, but will still throw if the WHOLE range is invalid. - .filter(c => c.length) - - if (!this.set.length) { - throw new TypeError(`Invalid SemVer Range: ${this.raw}`) - } - - // if we have any that are not the null set, throw out null sets. - if (this.set.length > 1) { - // keep the first one, in case they're all null sets - const first = this.set[0] - this.set = this.set.filter(c => !isNullSet(c[0])) - if (this.set.length === 0) { - this.set = [first] - } else if (this.set.length > 1) { - // if we have any that are *, then the range is just * - for (const c of this.set) { - if (c.length === 1 && isAny(c[0])) { - this.set = [c] - break - } - } - } - } - - this.formatted = undefined - } - - get range () { - if (this.formatted === undefined) { - this.formatted = '' - for (let i = 0; i < this.set.length; i++) { - if (i > 0) { - this.formatted += '||' - } - const comps = this.set[i] - for (let k = 0; k < comps.length; k++) { - if (k > 0) { - this.formatted += ' ' - } - this.formatted += comps[k].toString().trim() - } - } - } - return this.formatted - } - - format () { - return this.range - } - - toString () { - return this.range - } - - parseRange (range) { - // memoize range parsing for performance. - // this is a very hot path, and fully deterministic. - const memoOpts = - (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | - (this.options.loose && FLAG_LOOSE) - const memoKey = memoOpts + ':' + range - const cached = cache.get(memoKey) - if (cached) { - return cached - } - - const loose = this.options.loose - // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE] - range = range.replace(hr, hyphenReplace(this.options.includePrerelease)) - debug('hyphen replace', range) - - // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace) - debug('comparator trim', range) - - // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[t.TILDETRIM], tildeTrimReplace) - debug('tilde trim', range) - - // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[t.CARETTRIM], caretTrimReplace) - debug('caret trim', range) - - // At this point, the range is completely trimmed and - // ready to be split into comparators. - - let rangeList = range - .split(' ') - .map(comp => parseComparator(comp, this.options)) - .join(' ') - .split(/\s+/) - // >=0.0.0 is equivalent to * - .map(comp => replaceGTE0(comp, this.options)) - - if (loose) { - // in loose mode, throw out any that are not valid comparators - rangeList = rangeList.filter(comp => { - debug('loose invalid filter', comp, this.options) - return !!comp.match(re[t.COMPARATORLOOSE]) - }) - } - debug('range list', rangeList) - - // if any comparators are the null set, then replace with JUST null set - // if more than one comparator, remove any * comparators - // also, don't include the same comparator more than once - const rangeMap = new Map() - const comparators = rangeList.map(comp => new Comparator(comp, this.options)) - for (const comp of comparators) { - if (isNullSet(comp)) { - return [comp] - } - rangeMap.set(comp.value, comp) - } - if (rangeMap.size > 1 && rangeMap.has('')) { - rangeMap.delete('') - } - - const result = [...rangeMap.values()] - cache.set(memoKey, result) - return result - } - - intersects (range, options) { - if (!(range instanceof Range)) { - throw new TypeError('a Range is required') - } - - return this.set.some((thisComparators) => { - return ( - isSatisfiable(thisComparators, options) && - range.set.some((rangeComparators) => { - return ( - isSatisfiable(rangeComparators, options) && - thisComparators.every((thisComparator) => { - return rangeComparators.every((rangeComparator) => { - return thisComparator.intersects(rangeComparator, options) - }) - }) - ) - }) - ) - }) - } - - // if ANY of the sets match ALL of its comparators, then pass - test (version) { - if (!version) { - return false - } - - if (typeof version === 'string') { - try { - version = new SemVer(version, this.options) - } catch (er) { - return false - } - } - - for (let i = 0; i < this.set.length; i++) { - if (testSet(this.set[i], version, this.options)) { - return true - } - } - return false - } -} - -module.exports = Range - -const LRU = __nccwpck_require__(8554) -const cache = new LRU() - -const parseOptions = __nccwpck_require__(5547) -const Comparator = __nccwpck_require__(6688) -const debug = __nccwpck_require__(9576) -const SemVer = __nccwpck_require__(6868) -const { - safeRe: re, - t, - comparatorTrimReplace, - tildeTrimReplace, - caretTrimReplace, -} = __nccwpck_require__(4326) -const { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = __nccwpck_require__(9498) - -const isNullSet = c => c.value === '<0.0.0-0' -const isAny = c => c.value === '' - -// take a set of comparators and determine whether there -// exists a version which can satisfy it -const isSatisfiable = (comparators, options) => { - let result = true - const remainingComparators = comparators.slice() - let testComparator = remainingComparators.pop() - - while (result && remainingComparators.length) { - result = remainingComparators.every((otherComparator) => { - return testComparator.intersects(otherComparator, options) - }) - - testComparator = remainingComparators.pop() - } - - return result -} - -// comprised of xranges, tildes, stars, and gtlt's at this point. -// already replaced the hyphen ranges -// turn into a set of JUST comparators. -const parseComparator = (comp, options) => { - debug('comp', comp, options) - comp = replaceCarets(comp, options) - debug('caret', comp) - comp = replaceTildes(comp, options) - debug('tildes', comp) - comp = replaceXRanges(comp, options) - debug('xrange', comp) - comp = replaceStars(comp, options) - debug('stars', comp) - return comp -} - -const isX = id => !id || id.toLowerCase() === 'x' || id === '*' - -// ~, ~> --> * (any, kinda silly) -// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0 -// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0 -// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0 -// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0 -// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0 -// ~0.0.1 --> >=0.0.1 <0.1.0-0 -const replaceTildes = (comp, options) => { - return comp - .trim() - .split(/\s+/) - .map((c) => replaceTilde(c, options)) - .join(' ') -} - -const replaceTilde = (comp, options) => { - const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE] - return comp.replace(r, (_, M, m, p, pr) => { - debug('tilde', comp, _, M, m, p, pr) - let ret - - if (isX(M)) { - ret = '' - } else if (isX(m)) { - ret = `>=${M}.0.0 <${+M + 1}.0.0-0` - } else if (isX(p)) { - // ~1.2 == >=1.2.0 <1.3.0-0 - ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0` - } else if (pr) { - debug('replaceTilde pr', pr) - ret = `>=${M}.${m}.${p}-${pr - } <${M}.${+m + 1}.0-0` - } else { - // ~1.2.3 == >=1.2.3 <1.3.0-0 - ret = `>=${M}.${m}.${p - } <${M}.${+m + 1}.0-0` - } - - debug('tilde return', ret) - return ret - }) -} - -// ^ --> * (any, kinda silly) -// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0 -// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0 -// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0 -// ^1.2.3 --> >=1.2.3 <2.0.0-0 -// ^1.2.0 --> >=1.2.0 <2.0.0-0 -// ^0.0.1 --> >=0.0.1 <0.0.2-0 -// ^0.1.0 --> >=0.1.0 <0.2.0-0 -const replaceCarets = (comp, options) => { - return comp - .trim() - .split(/\s+/) - .map((c) => replaceCaret(c, options)) - .join(' ') -} - -const replaceCaret = (comp, options) => { - debug('caret', comp, options) - const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET] - const z = options.includePrerelease ? '-0' : '' - return comp.replace(r, (_, M, m, p, pr) => { - debug('caret', comp, _, M, m, p, pr) - let ret - - if (isX(M)) { - ret = '' - } else if (isX(m)) { - ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0` - } else if (isX(p)) { - if (M === '0') { - ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0` - } else { - ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0` - } - } else if (pr) { - debug('replaceCaret pr', pr) - if (M === '0') { - if (m === '0') { - ret = `>=${M}.${m}.${p}-${pr - } <${M}.${m}.${+p + 1}-0` - } else { - ret = `>=${M}.${m}.${p}-${pr - } <${M}.${+m + 1}.0-0` - } - } else { - ret = `>=${M}.${m}.${p}-${pr - } <${+M + 1}.0.0-0` - } - } else { - debug('no pr') - if (M === '0') { - if (m === '0') { - ret = `>=${M}.${m}.${p - }${z} <${M}.${m}.${+p + 1}-0` - } else { - ret = `>=${M}.${m}.${p - }${z} <${M}.${+m + 1}.0-0` - } - } else { - ret = `>=${M}.${m}.${p - } <${+M + 1}.0.0-0` - } - } - - debug('caret return', ret) - return ret - }) -} - -const replaceXRanges = (comp, options) => { - debug('replaceXRanges', comp, options) - return comp - .split(/\s+/) - .map((c) => replaceXRange(c, options)) - .join(' ') -} - -const replaceXRange = (comp, options) => { - comp = comp.trim() - const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE] - return comp.replace(r, (ret, gtlt, M, m, p, pr) => { - debug('xRange', comp, ret, gtlt, M, m, p, pr) - const xM = isX(M) - const xm = xM || isX(m) - const xp = xm || isX(p) - const anyX = xp - - if (gtlt === '=' && anyX) { - gtlt = '' - } - - // if we're including prereleases in the match, then we need - // to fix this to -0, the lowest possible prerelease value - pr = options.includePrerelease ? '-0' : '' - - if (xM) { - if (gtlt === '>' || gtlt === '<') { - // nothing is allowed - ret = '<0.0.0-0' - } else { - // nothing is forbidden - ret = '*' - } - } else if (gtlt && anyX) { - // we know patch is an x, because we have any x at all. - // replace X with 0 - if (xm) { - m = 0 - } - p = 0 - - if (gtlt === '>') { - // >1 => >=2.0.0 - // >1.2 => >=1.3.0 - gtlt = '>=' - if (xm) { - M = +M + 1 - m = 0 - p = 0 - } else { - m = +m + 1 - p = 0 - } - } else if (gtlt === '<=') { - // <=0.7.x is actually <0.8.0, since any 0.7.x should - // pass. Similarly, <=7.x is actually <8.0.0, etc. - gtlt = '<' - if (xm) { - M = +M + 1 - } else { - m = +m + 1 - } - } - - if (gtlt === '<') { - pr = '-0' - } - - ret = `${gtlt + M}.${m}.${p}${pr}` - } else if (xm) { - ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0` - } else if (xp) { - ret = `>=${M}.${m}.0${pr - } <${M}.${+m + 1}.0-0` - } - - debug('xRange return', ret) - - return ret - }) -} - -// Because * is AND-ed with everything else in the comparator, -// and '' means "any version", just remove the *s entirely. -const replaceStars = (comp, options) => { - debug('replaceStars', comp, options) - // Looseness is ignored here. star is always as loose as it gets! - return comp - .trim() - .replace(re[t.STAR], '') -} - -const replaceGTE0 = (comp, options) => { - debug('replaceGTE0', comp, options) - return comp - .trim() - .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '') -} - -// This function is passed to string.replace(re[t.HYPHENRANGE]) -// M, m, patch, prerelease, build -// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 -// 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do -// 1.2 - 3.4 => >=1.2.0 <3.5.0-0 -// TODO build? -const hyphenReplace = incPr => ($0, - from, fM, fm, fp, fpr, fb, - to, tM, tm, tp, tpr) => { - if (isX(fM)) { - from = '' - } else if (isX(fm)) { - from = `>=${fM}.0.0${incPr ? '-0' : ''}` - } else if (isX(fp)) { - from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}` - } else if (fpr) { - from = `>=${from}` - } else { - from = `>=${from}${incPr ? '-0' : ''}` - } - - if (isX(tM)) { - to = '' - } else if (isX(tm)) { - to = `<${+tM + 1}.0.0-0` - } else if (isX(tp)) { - to = `<${tM}.${+tm + 1}.0-0` - } else if (tpr) { - to = `<=${tM}.${tm}.${tp}-${tpr}` - } else if (incPr) { - to = `<${tM}.${tm}.${+tp + 1}-0` - } else { - to = `<=${to}` - } - - return `${from} ${to}`.trim() -} - -const testSet = (set, version, options) => { - for (let i = 0; i < set.length; i++) { - if (!set[i].test(version)) { - return false - } - } - - if (version.prerelease.length && !options.includePrerelease) { - // Find the set of versions that are allowed to have prereleases - // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 - // That should allow `1.2.3-pr.2` to pass. - // However, `1.2.4-alpha.notready` should NOT be allowed, - // even though it's within the range set by the comparators. - for (let i = 0; i < set.length; i++) { - debug(set[i].semver) - if (set[i].semver === Comparator.ANY) { - continue - } - - if (set[i].semver.prerelease.length > 0) { - const allowed = set[i].semver - if (allowed.major === version.major && - allowed.minor === version.minor && - allowed.patch === version.patch) { - return true - } - } - } - - // Version has a -pre, but it's not one of the ones we like. - return false - } - - return true -} - - -/***/ }), - -/***/ 6868: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const debug = __nccwpck_require__(9576) -const { MAX_LENGTH, MAX_SAFE_INTEGER } = __nccwpck_require__(9498) -const { safeRe: re, t } = __nccwpck_require__(4326) - -const parseOptions = __nccwpck_require__(5547) -const { compareIdentifiers } = __nccwpck_require__(7235) -class SemVer { - constructor (version, options) { - options = parseOptions(options) - - if (version instanceof SemVer) { - if (version.loose === !!options.loose && - version.includePrerelease === !!options.includePrerelease) { - return version - } else { - version = version.version - } - } else if (typeof version !== 'string') { - throw new TypeError(`Invalid version. Must be a string. Got type "${typeof version}".`) - } - - if (version.length > MAX_LENGTH) { - throw new TypeError( - `version is longer than ${MAX_LENGTH} characters` - ) - } - - debug('SemVer', version, options) - this.options = options - this.loose = !!options.loose - // this isn't actually relevant for versions, but keep it so that we - // don't run into trouble passing this.options around. - this.includePrerelease = !!options.includePrerelease - - const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]) - - if (!m) { - throw new TypeError(`Invalid Version: ${version}`) - } - - this.raw = version - - // these are actually numbers - this.major = +m[1] - this.minor = +m[2] - this.patch = +m[3] - - if (this.major > MAX_SAFE_INTEGER || this.major < 0) { - throw new TypeError('Invalid major version') - } - - if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { - throw new TypeError('Invalid minor version') - } - - if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { - throw new TypeError('Invalid patch version') - } - - // numberify any prerelease numeric ids - if (!m[4]) { - this.prerelease = [] - } else { - this.prerelease = m[4].split('.').map((id) => { - if (/^[0-9]+$/.test(id)) { - const num = +id - if (num >= 0 && num < MAX_SAFE_INTEGER) { - return num - } - } - return id - }) - } - - this.build = m[5] ? m[5].split('.') : [] - this.format() - } - - format () { - this.version = `${this.major}.${this.minor}.${this.patch}` - if (this.prerelease.length) { - this.version += `-${this.prerelease.join('.')}` - } - return this.version - } - - toString () { - return this.version - } - - compare (other) { - debug('SemVer.compare', this.version, this.options, other) - if (!(other instanceof SemVer)) { - if (typeof other === 'string' && other === this.version) { - return 0 - } - other = new SemVer(other, this.options) - } - - if (other.version === this.version) { - return 0 - } - - return this.compareMain(other) || this.comparePre(other) - } - - compareMain (other) { - if (!(other instanceof SemVer)) { - other = new SemVer(other, this.options) - } - - return ( - compareIdentifiers(this.major, other.major) || - compareIdentifiers(this.minor, other.minor) || - compareIdentifiers(this.patch, other.patch) - ) - } - - comparePre (other) { - if (!(other instanceof SemVer)) { - other = new SemVer(other, this.options) - } - - // NOT having a prerelease is > having one - if (this.prerelease.length && !other.prerelease.length) { - return -1 - } else if (!this.prerelease.length && other.prerelease.length) { - return 1 - } else if (!this.prerelease.length && !other.prerelease.length) { - return 0 - } - - let i = 0 - do { - const a = this.prerelease[i] - const b = other.prerelease[i] - debug('prerelease compare', i, a, b) - if (a === undefined && b === undefined) { - return 0 - } else if (b === undefined) { - return 1 - } else if (a === undefined) { - return -1 - } else if (a === b) { - continue - } else { - return compareIdentifiers(a, b) - } - } while (++i) - } - - compareBuild (other) { - if (!(other instanceof SemVer)) { - other = new SemVer(other, this.options) - } - - let i = 0 - do { - const a = this.build[i] - const b = other.build[i] - debug('build compare', i, a, b) - if (a === undefined && b === undefined) { - return 0 - } else if (b === undefined) { - return 1 - } else if (a === undefined) { - return -1 - } else if (a === b) { - continue - } else { - return compareIdentifiers(a, b) - } - } while (++i) - } - - // preminor will bump the version up to the next minor release, and immediately - // down to pre-release. premajor and prepatch work the same way. - inc (release, identifier, identifierBase) { - if (release.startsWith('pre')) { - if (!identifier && identifierBase === false) { - throw new Error('invalid increment argument: identifier is empty') - } - // Avoid an invalid semver results - if (identifier) { - const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE]) - if (!match || match[1] !== identifier) { - throw new Error(`invalid identifier: ${identifier}`) - } - } - } - - switch (release) { - case 'premajor': - this.prerelease.length = 0 - this.patch = 0 - this.minor = 0 - this.major++ - this.inc('pre', identifier, identifierBase) - break - case 'preminor': - this.prerelease.length = 0 - this.patch = 0 - this.minor++ - this.inc('pre', identifier, identifierBase) - break - case 'prepatch': - // If this is already a prerelease, it will bump to the next version - // drop any prereleases that might already exist, since they are not - // relevant at this point. - this.prerelease.length = 0 - this.inc('patch', identifier, identifierBase) - this.inc('pre', identifier, identifierBase) - break - // If the input is a non-prerelease version, this acts the same as - // prepatch. - case 'prerelease': - if (this.prerelease.length === 0) { - this.inc('patch', identifier, identifierBase) - } - this.inc('pre', identifier, identifierBase) - break - case 'release': - if (this.prerelease.length === 0) { - throw new Error(`version ${this.raw} is not a prerelease`) - } - this.prerelease.length = 0 - break - - case 'major': - // If this is a pre-major version, bump up to the same major version. - // Otherwise increment major. - // 1.0.0-5 bumps to 1.0.0 - // 1.1.0 bumps to 2.0.0 - if ( - this.minor !== 0 || - this.patch !== 0 || - this.prerelease.length === 0 - ) { - this.major++ - } - this.minor = 0 - this.patch = 0 - this.prerelease = [] - break - case 'minor': - // If this is a pre-minor version, bump up to the same minor version. - // Otherwise increment minor. - // 1.2.0-5 bumps to 1.2.0 - // 1.2.1 bumps to 1.3.0 - if (this.patch !== 0 || this.prerelease.length === 0) { - this.minor++ - } - this.patch = 0 - this.prerelease = [] - break - case 'patch': - // If this is not a pre-release version, it will increment the patch. - // If it is a pre-release it will bump up to the same patch version. - // 1.2.0-5 patches to 1.2.0 - // 1.2.0 patches to 1.2.1 - if (this.prerelease.length === 0) { - this.patch++ - } - this.prerelease = [] - break - // This probably shouldn't be used publicly. - // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction. - case 'pre': { - const base = Number(identifierBase) ? 1 : 0 - - if (this.prerelease.length === 0) { - this.prerelease = [base] - } else { - let i = this.prerelease.length - while (--i >= 0) { - if (typeof this.prerelease[i] === 'number') { - this.prerelease[i]++ - i = -2 - } - } - if (i === -1) { - // didn't increment anything - if (identifier === this.prerelease.join('.') && identifierBase === false) { - throw new Error('invalid increment argument: identifier already exists') - } - this.prerelease.push(base) - } - } - if (identifier) { - // 1.2.0-beta.1 bumps to 1.2.0-beta.2, - // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 - let prerelease = [identifier, base] - if (identifierBase === false) { - prerelease = [identifier] - } - if (compareIdentifiers(this.prerelease[0], identifier) === 0) { - if (isNaN(this.prerelease[1])) { - this.prerelease = prerelease - } - } else { - this.prerelease = prerelease - } - } - break - } - default: - throw new Error(`invalid increment argument: ${release}`) - } - this.raw = this.format() - if (this.build.length) { - this.raw += `+${this.build.join('.')}` - } - return this - } -} - -module.exports = SemVer - - -/***/ }), - -/***/ 3686: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const parse = __nccwpck_require__(9088) -const clean = (version, options) => { - const s = parse(version.trim().replace(/^[=v]+/, ''), options) - return s ? s.version : null -} -module.exports = clean - - -/***/ }), - -/***/ 3663: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const eq = __nccwpck_require__(6033) -const neq = __nccwpck_require__(1055) -const gt = __nccwpck_require__(3932) -const gte = __nccwpck_require__(2505) -const lt = __nccwpck_require__(6707) -const lte = __nccwpck_require__(3296) - -const cmp = (a, op, b, loose) => { - switch (op) { - case '===': - if (typeof a === 'object') { - a = a.version - } - if (typeof b === 'object') { - b = b.version - } - return a === b - - case '!==': - if (typeof a === 'object') { - a = a.version - } - if (typeof b === 'object') { - b = b.version - } - return a !== b - - case '': - case '=': - case '==': - return eq(a, b, loose) - - case '!=': - return neq(a, b, loose) - - case '>': - return gt(a, b, loose) - - case '>=': - return gte(a, b, loose) - - case '<': - return lt(a, b, loose) - - case '<=': - return lte(a, b, loose) - - default: - throw new TypeError(`Invalid operator: ${op}`) - } -} -module.exports = cmp - - -/***/ }), - -/***/ 6093: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const parse = __nccwpck_require__(9088) -const { safeRe: re, t } = __nccwpck_require__(4326) - -const coerce = (version, options) => { - if (version instanceof SemVer) { - return version - } - - if (typeof version === 'number') { - version = String(version) - } - - if (typeof version !== 'string') { - return null - } - - options = options || {} - - let match = null - if (!options.rtl) { - match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE]) - } else { - // Find the right-most coercible string that does not share - // a terminus with a more left-ward coercible string. - // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' - // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4' - // - // Walk through the string checking with a /g regexp - // Manually set the index so as to pick up overlapping matches. - // Stop when we get a match that ends at the string end, since no - // coercible string can be more right-ward without the same terminus. - const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL] - let next - while ((next = coerceRtlRegex.exec(version)) && - (!match || match.index + match[0].length !== version.length) - ) { - if (!match || - next.index + next[0].length !== match.index + match[0].length) { - match = next - } - coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length - } - // leave it in a clean state - coerceRtlRegex.lastIndex = -1 - } - - if (match === null) { - return null - } - - const major = match[2] - const minor = match[3] || '0' - const patch = match[4] || '0' - const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : '' - const build = options.includePrerelease && match[6] ? `+${match[6]}` : '' - - return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options) -} -module.exports = coerce - - -/***/ }), - -/***/ 4797: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const compareBuild = (a, b, loose) => { - const versionA = new SemVer(a, loose) - const versionB = new SemVer(b, loose) - return versionA.compare(versionB) || versionA.compareBuild(versionB) -} -module.exports = compareBuild - - -/***/ }), - -/***/ 2931: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const compareLoose = (a, b) => compare(a, b, true) -module.exports = compareLoose - - -/***/ }), - -/***/ 8224: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const compare = (a, b, loose) => - new SemVer(a, loose).compare(new SemVer(b, loose)) - -module.exports = compare - - -/***/ }), - -/***/ 3464: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const parse = __nccwpck_require__(9088) - -const diff = (version1, version2) => { - const v1 = parse(version1, null, true) - const v2 = parse(version2, null, true) - const comparison = v1.compare(v2) - - if (comparison === 0) { - return null - } - - const v1Higher = comparison > 0 - const highVersion = v1Higher ? v1 : v2 - const lowVersion = v1Higher ? v2 : v1 - const highHasPre = !!highVersion.prerelease.length - const lowHasPre = !!lowVersion.prerelease.length - - if (lowHasPre && !highHasPre) { - // Going from prerelease -> no prerelease requires some special casing - - // If the low version has only a major, then it will always be a major - // Some examples: - // 1.0.0-1 -> 1.0.0 - // 1.0.0-1 -> 1.1.1 - // 1.0.0-1 -> 2.0.0 - if (!lowVersion.patch && !lowVersion.minor) { - return 'major' - } - - // If the main part has no difference - if (lowVersion.compareMain(highVersion) === 0) { - if (lowVersion.minor && !lowVersion.patch) { - return 'minor' - } - return 'patch' - } - } - - // add the `pre` prefix if we are going to a prerelease version - const prefix = highHasPre ? 'pre' : '' - - if (v1.major !== v2.major) { - return prefix + 'major' - } - - if (v1.minor !== v2.minor) { - return prefix + 'minor' - } - - if (v1.patch !== v2.patch) { - return prefix + 'patch' - } - - // high and low are preleases - return 'prerelease' -} - -module.exports = diff - - -/***/ }), - -/***/ 6033: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const eq = (a, b, loose) => compare(a, b, loose) === 0 -module.exports = eq - - -/***/ }), - -/***/ 3932: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const gt = (a, b, loose) => compare(a, b, loose) > 0 -module.exports = gt - - -/***/ }), - -/***/ 2505: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const gte = (a, b, loose) => compare(a, b, loose) >= 0 -module.exports = gte - - -/***/ }), - -/***/ 7503: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) - -const inc = (version, release, options, identifier, identifierBase) => { - if (typeof (options) === 'string') { - identifierBase = identifier - identifier = options - options = undefined - } - - try { - return new SemVer( - version instanceof SemVer ? version.version : version, - options - ).inc(release, identifier, identifierBase).version - } catch (er) { - return null - } -} -module.exports = inc - - -/***/ }), - -/***/ 6707: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const lt = (a, b, loose) => compare(a, b, loose) < 0 -module.exports = lt - - -/***/ }), - -/***/ 3296: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const lte = (a, b, loose) => compare(a, b, loose) <= 0 -module.exports = lte - - -/***/ }), - -/***/ 5866: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const major = (a, loose) => new SemVer(a, loose).major -module.exports = major - - -/***/ }), - -/***/ 4238: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const minor = (a, loose) => new SemVer(a, loose).minor -module.exports = minor - - -/***/ }), - -/***/ 1055: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const neq = (a, b, loose) => compare(a, b, loose) !== 0 -module.exports = neq - - -/***/ }), - -/***/ 9088: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const parse = (version, options, throwErrors = false) => { - if (version instanceof SemVer) { - return version - } - try { - return new SemVer(version, options) - } catch (er) { - if (!throwErrors) { - return null - } - throw er - } -} - -module.exports = parse - - -/***/ }), - -/***/ 61: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const patch = (a, loose) => new SemVer(a, loose).patch -module.exports = patch - - -/***/ }), - -/***/ 2321: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const parse = __nccwpck_require__(9088) -const prerelease = (version, options) => { - const parsed = parse(version, options) - return (parsed && parsed.prerelease.length) ? parsed.prerelease : null -} -module.exports = prerelease - - -/***/ }), - -/***/ 5042: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compare = __nccwpck_require__(8224) -const rcompare = (a, b, loose) => compare(b, a, loose) -module.exports = rcompare - - -/***/ }), - -/***/ 6005: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compareBuild = __nccwpck_require__(4797) -const rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose)) -module.exports = rsort - - -/***/ }), - -/***/ 3462: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Range = __nccwpck_require__(3892) -const satisfies = (version, range, options) => { - try { - range = new Range(range, options) - } catch (er) { - return false - } - return range.test(version) -} -module.exports = satisfies - - -/***/ }), - -/***/ 2071: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const compareBuild = __nccwpck_require__(4797) -const sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose)) -module.exports = sort - - -/***/ }), - -/***/ 4713: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const parse = __nccwpck_require__(9088) -const valid = (version, options) => { - const v = parse(version, options) - return v ? v.version : null -} -module.exports = valid - - -/***/ }), - -/***/ 3781: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -// just pre-load all the stuff that index.js lazily exports -const internalRe = __nccwpck_require__(4326) -const constants = __nccwpck_require__(9498) -const SemVer = __nccwpck_require__(6868) -const identifiers = __nccwpck_require__(7235) -const parse = __nccwpck_require__(9088) -const valid = __nccwpck_require__(4713) -const clean = __nccwpck_require__(3686) -const inc = __nccwpck_require__(7503) -const diff = __nccwpck_require__(3464) -const major = __nccwpck_require__(5866) -const minor = __nccwpck_require__(4238) -const patch = __nccwpck_require__(61) -const prerelease = __nccwpck_require__(2321) -const compare = __nccwpck_require__(8224) -const rcompare = __nccwpck_require__(5042) -const compareLoose = __nccwpck_require__(2931) -const compareBuild = __nccwpck_require__(4797) -const sort = __nccwpck_require__(2071) -const rsort = __nccwpck_require__(6005) -const gt = __nccwpck_require__(3932) -const lt = __nccwpck_require__(6707) -const eq = __nccwpck_require__(6033) -const neq = __nccwpck_require__(1055) -const gte = __nccwpck_require__(2505) -const lte = __nccwpck_require__(3296) -const cmp = __nccwpck_require__(3663) -const coerce = __nccwpck_require__(6093) -const Comparator = __nccwpck_require__(6688) -const Range = __nccwpck_require__(3892) -const satisfies = __nccwpck_require__(3462) -const toComparators = __nccwpck_require__(4975) -const maxSatisfying = __nccwpck_require__(8636) -const minSatisfying = __nccwpck_require__(4014) -const minVersion = __nccwpck_require__(8525) -const validRange = __nccwpck_require__(1106) -const outside = __nccwpck_require__(6227) -const gtr = __nccwpck_require__(899) -const ltr = __nccwpck_require__(9982) -const intersects = __nccwpck_require__(8716) -const simplifyRange = __nccwpck_require__(3117) -const subset = __nccwpck_require__(680) -module.exports = { - parse, - valid, - clean, - inc, - diff, - major, - minor, - patch, - prerelease, - compare, - rcompare, - compareLoose, - compareBuild, - sort, - rsort, - gt, - lt, - eq, - neq, - gte, - lte, - cmp, - coerce, - Comparator, - Range, - satisfies, - toComparators, - maxSatisfying, - minSatisfying, - minVersion, - validRange, - outside, - gtr, - ltr, - intersects, - simplifyRange, - subset, - SemVer, - re: internalRe.re, - src: internalRe.src, - tokens: internalRe.t, - SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION, - RELEASE_TYPES: constants.RELEASE_TYPES, - compareIdentifiers: identifiers.compareIdentifiers, - rcompareIdentifiers: identifiers.rcompareIdentifiers, -} - - -/***/ }), - -/***/ 9498: -/***/ ((module) => { - -"use strict"; - - -// Note: this is the semver.org version of the spec that it implements -// Not necessarily the package version of this code. -const SEMVER_SPEC_VERSION = '2.0.0' - -const MAX_LENGTH = 256 -const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || -/* istanbul ignore next */ 9007199254740991 - -// Max safe segment length for coercion. -const MAX_SAFE_COMPONENT_LENGTH = 16 - -// Max safe length for a build identifier. The max length minus 6 characters for -// the shortest version with a build 0.0.0+BUILD. -const MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6 - -const RELEASE_TYPES = [ - 'major', - 'premajor', - 'minor', - 'preminor', - 'patch', - 'prepatch', - 'prerelease', -] - -module.exports = { - MAX_LENGTH, - MAX_SAFE_COMPONENT_LENGTH, - MAX_SAFE_BUILD_LENGTH, - MAX_SAFE_INTEGER, - RELEASE_TYPES, - SEMVER_SPEC_VERSION, - FLAG_INCLUDE_PRERELEASE: 0b001, - FLAG_LOOSE: 0b010, -} - - -/***/ }), - -/***/ 9576: -/***/ ((module) => { - -"use strict"; - - -const debug = ( - typeof process === 'object' && - process.env && - process.env.NODE_DEBUG && - /\bsemver\b/i.test(process.env.NODE_DEBUG) -) ? (...args) => console.error('SEMVER', ...args) - : () => {} - -module.exports = debug - - -/***/ }), - -/***/ 7235: -/***/ ((module) => { - -"use strict"; - - -const numeric = /^[0-9]+$/ -const compareIdentifiers = (a, b) => { - const anum = numeric.test(a) - const bnum = numeric.test(b) - - if (anum && bnum) { - a = +a - b = +b - } - - return a === b ? 0 - : (anum && !bnum) ? -1 - : (bnum && !anum) ? 1 - : a < b ? -1 - : 1 -} - -const rcompareIdentifiers = (a, b) => compareIdentifiers(b, a) - -module.exports = { - compareIdentifiers, - rcompareIdentifiers, -} - - -/***/ }), - -/***/ 8554: -/***/ ((module) => { - -"use strict"; - - -class LRUCache { - constructor () { - this.max = 1000 - this.map = new Map() - } - - get (key) { - const value = this.map.get(key) - if (value === undefined) { - return undefined - } else { - // Remove the key from the map and add it to the end - this.map.delete(key) - this.map.set(key, value) - return value - } - } - - delete (key) { - return this.map.delete(key) - } - - set (key, value) { - const deleted = this.delete(key) - - if (!deleted && value !== undefined) { - // If cache is full, delete the least recently used item - if (this.map.size >= this.max) { - const firstKey = this.map.keys().next().value - this.delete(firstKey) - } - - this.map.set(key, value) - } - - return this - } -} - -module.exports = LRUCache - - -/***/ }), - -/***/ 5547: -/***/ ((module) => { - -"use strict"; - - -// parse out just the options we care about -const looseOption = Object.freeze({ loose: true }) -const emptyOpts = Object.freeze({ }) -const parseOptions = options => { - if (!options) { - return emptyOpts - } - - if (typeof options !== 'object') { - return looseOption - } - - return options -} -module.exports = parseOptions - - -/***/ }), - -/***/ 4326: -/***/ ((module, exports, __nccwpck_require__) => { - -"use strict"; - - -const { - MAX_SAFE_COMPONENT_LENGTH, - MAX_SAFE_BUILD_LENGTH, - MAX_LENGTH, -} = __nccwpck_require__(9498) -const debug = __nccwpck_require__(9576) -exports = module.exports = {} - -// The actual regexps go on exports.re -const re = exports.re = [] -const safeRe = exports.safeRe = [] -const src = exports.src = [] -const safeSrc = exports.safeSrc = [] -const t = exports.t = {} -let R = 0 - -const LETTERDASHNUMBER = '[a-zA-Z0-9-]' - -// Replace some greedy regex tokens to prevent regex dos issues. These regex are -// used internally via the safeRe object since all inputs in this library get -// normalized first to trim and collapse all extra whitespace. The original -// regexes are exported for userland consumption and lower level usage. A -// future breaking change could export the safer regex only with a note that -// all input should have extra whitespace removed. -const safeRegexReplacements = [ - ['\\s', 1], - ['\\d', MAX_LENGTH], - [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH], -] - -const makeSafeRegex = (value) => { - for (const [token, max] of safeRegexReplacements) { - value = value - .split(`${token}*`).join(`${token}{0,${max}}`) - .split(`${token}+`).join(`${token}{1,${max}}`) - } - return value -} - -const createToken = (name, value, isGlobal) => { - const safe = makeSafeRegex(value) - const index = R++ - debug(name, index, value) - t[name] = index - src[index] = value - safeSrc[index] = safe - re[index] = new RegExp(value, isGlobal ? 'g' : undefined) - safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined) -} - -// The following Regular Expressions can be used for tokenizing, -// validating, and parsing SemVer version strings. - -// ## Numeric Identifier -// A single `0`, or a non-zero digit followed by zero or more digits. - -createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*') -createToken('NUMERICIDENTIFIERLOOSE', '\\d+') - -// ## Non-numeric Identifier -// Zero or more digits, followed by a letter or hyphen, and then zero or -// more letters, digits, or hyphens. - -createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`) - -// ## Main Version -// Three dot-separated numeric identifiers. - -createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` + - `(${src[t.NUMERICIDENTIFIER]})\\.` + - `(${src[t.NUMERICIDENTIFIER]})`) - -createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + - `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` + - `(${src[t.NUMERICIDENTIFIERLOOSE]})`) - -// ## Pre-release Version Identifier -// A numeric identifier, or a non-numeric identifier. -// Non-numberic identifiers include numberic identifiers but can be longer. -// Therefore non-numberic identifiers must go first. - -createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER] -}|${src[t.NUMERICIDENTIFIER]})`) - -createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER] -}|${src[t.NUMERICIDENTIFIERLOOSE]})`) - -// ## Pre-release Version -// Hyphen, followed by one or more dot-separated pre-release version -// identifiers. - -createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER] -}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`) - -createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE] -}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`) - -// ## Build Metadata Identifier -// Any combination of digits, letters, or hyphens. - -createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`) - -// ## Build Metadata -// Plus sign, followed by one or more period-separated build metadata -// identifiers. - -createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER] -}(?:\\.${src[t.BUILDIDENTIFIER]})*))`) - -// ## Full Version String -// A main version, followed optionally by a pre-release version and -// build metadata. - -// Note that the only major, minor, patch, and pre-release sections of -// the version string are capturing groups. The build metadata is not a -// capturing group, because it should not ever be used in version -// comparison. - -createToken('FULLPLAIN', `v?${src[t.MAINVERSION] -}${src[t.PRERELEASE]}?${ - src[t.BUILD]}?`) - -createToken('FULL', `^${src[t.FULLPLAIN]}$`) - -// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. -// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty -// common in the npm registry. -createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE] -}${src[t.PRERELEASELOOSE]}?${ - src[t.BUILD]}?`) - -createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`) - -createToken('GTLT', '((?:<|>)?=?)') - -// Something like "2.*" or "1.2.x". -// Note that "x.x" is a valid xRange identifer, meaning "any version" -// Only the first item is strictly required. -createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`) -createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`) - -createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` + - `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + - `(?:\\.(${src[t.XRANGEIDENTIFIER]})` + - `(?:${src[t.PRERELEASE]})?${ - src[t.BUILD]}?` + - `)?)?`) - -createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` + - `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + - `(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` + - `(?:${src[t.PRERELEASELOOSE]})?${ - src[t.BUILD]}?` + - `)?)?`) - -createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`) -createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`) - -// Coercion. -// Extract anything that could conceivably be a part of a valid semver -createToken('COERCEPLAIN', `${'(^|[^\\d])' + - '(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` + - `(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`) -createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`) -createToken('COERCEFULL', src[t.COERCEPLAIN] + - `(?:${src[t.PRERELEASE]})?` + - `(?:${src[t.BUILD]})?` + - `(?:$|[^\\d])`) -createToken('COERCERTL', src[t.COERCE], true) -createToken('COERCERTLFULL', src[t.COERCEFULL], true) - -// Tilde ranges. -// Meaning is "reasonably at or greater than" -createToken('LONETILDE', '(?:~>?)') - -createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true) -exports.tildeTrimReplace = '$1~' - -createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`) -createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`) - -// Caret ranges. -// Meaning is "at least and backwards compatible with" -createToken('LONECARET', '(?:\\^)') - -createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true) -exports.caretTrimReplace = '$1^' - -createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`) -createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`) - -// A simple gt/lt/eq thing, or just "" to indicate "any version" -createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`) -createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`) - -// An expression to strip any whitespace between the gtlt and the thing -// it modifies, so that `> 1.2.3` ==> `>1.2.3` -createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT] -}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true) -exports.comparatorTrimReplace = '$1$2$3' - -// Something like `1.2.3 - 1.2.4` -// Note that these all use the loose form, because they'll be -// checked against either the strict or loose comparator form -// later. -createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` + - `\\s+-\\s+` + - `(${src[t.XRANGEPLAIN]})` + - `\\s*$`) - -createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` + - `\\s+-\\s+` + - `(${src[t.XRANGEPLAINLOOSE]})` + - `\\s*$`) - -// Star ranges basically just allow anything at all. -createToken('STAR', '(<|>)?=?\\s*\\*') -// >=0.0.0 is like a star -createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$') -createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$') - - -/***/ }), - -/***/ 899: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -// Determine if version is greater than all the versions possible in the range. -const outside = __nccwpck_require__(6227) -const gtr = (version, range, options) => outside(version, range, '>', options) -module.exports = gtr - - -/***/ }), - -/***/ 8716: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Range = __nccwpck_require__(3892) -const intersects = (r1, r2, options) => { - r1 = new Range(r1, options) - r2 = new Range(r2, options) - return r1.intersects(r2, options) -} -module.exports = intersects - - -/***/ }), - -/***/ 9982: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const outside = __nccwpck_require__(6227) -// Determine if version is less than all the versions possible in the range -const ltr = (version, range, options) => outside(version, range, '<', options) -module.exports = ltr - - -/***/ }), - -/***/ 8636: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const Range = __nccwpck_require__(3892) - -const maxSatisfying = (versions, range, options) => { - let max = null - let maxSV = null - let rangeObj = null - try { - rangeObj = new Range(range, options) - } catch (er) { - return null - } - versions.forEach((v) => { - if (rangeObj.test(v)) { - // satisfies(v, range, options) - if (!max || maxSV.compare(v) === -1) { - // compare(max, v, true) - max = v - maxSV = new SemVer(max, options) - } - } - }) - return max -} -module.exports = maxSatisfying - - -/***/ }), - -/***/ 4014: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const Range = __nccwpck_require__(3892) -const minSatisfying = (versions, range, options) => { - let min = null - let minSV = null - let rangeObj = null - try { - rangeObj = new Range(range, options) - } catch (er) { - return null - } - versions.forEach((v) => { - if (rangeObj.test(v)) { - // satisfies(v, range, options) - if (!min || minSV.compare(v) === 1) { - // compare(min, v, true) - min = v - minSV = new SemVer(min, options) - } - } - }) - return min -} -module.exports = minSatisfying - - -/***/ }), - -/***/ 8525: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const Range = __nccwpck_require__(3892) -const gt = __nccwpck_require__(3932) - -const minVersion = (range, loose) => { - range = new Range(range, loose) - - let minver = new SemVer('0.0.0') - if (range.test(minver)) { - return minver - } - - minver = new SemVer('0.0.0-0') - if (range.test(minver)) { - return minver - } - - minver = null - for (let i = 0; i < range.set.length; ++i) { - const comparators = range.set[i] - - let setMin = null - comparators.forEach((comparator) => { - // Clone to avoid manipulating the comparator's semver object. - const compver = new SemVer(comparator.semver.version) - switch (comparator.operator) { - case '>': - if (compver.prerelease.length === 0) { - compver.patch++ - } else { - compver.prerelease.push(0) - } - compver.raw = compver.format() - /* fallthrough */ - case '': - case '>=': - if (!setMin || gt(compver, setMin)) { - setMin = compver - } - break - case '<': - case '<=': - /* Ignore maximum versions */ - break - /* istanbul ignore next */ - default: - throw new Error(`Unexpected operation: ${comparator.operator}`) - } - }) - if (setMin && (!minver || gt(minver, setMin))) { - minver = setMin - } - } - - if (minver && range.test(minver)) { - return minver - } - - return null -} -module.exports = minVersion - - -/***/ }), - -/***/ 6227: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const SemVer = __nccwpck_require__(6868) -const Comparator = __nccwpck_require__(6688) -const { ANY } = Comparator -const Range = __nccwpck_require__(3892) -const satisfies = __nccwpck_require__(3462) -const gt = __nccwpck_require__(3932) -const lt = __nccwpck_require__(6707) -const lte = __nccwpck_require__(3296) -const gte = __nccwpck_require__(2505) - -const outside = (version, range, hilo, options) => { - version = new SemVer(version, options) - range = new Range(range, options) - - let gtfn, ltefn, ltfn, comp, ecomp - switch (hilo) { - case '>': - gtfn = gt - ltefn = lte - ltfn = lt - comp = '>' - ecomp = '>=' - break - case '<': - gtfn = lt - ltefn = gte - ltfn = gt - comp = '<' - ecomp = '<=' - break - default: - throw new TypeError('Must provide a hilo val of "<" or ">"') - } - - // If it satisfies the range it is not outside - if (satisfies(version, range, options)) { - return false - } - - // From now on, variable terms are as if we're in "gtr" mode. - // but note that everything is flipped for the "ltr" function. - - for (let i = 0; i < range.set.length; ++i) { - const comparators = range.set[i] - - let high = null - let low = null - - comparators.forEach((comparator) => { - if (comparator.semver === ANY) { - comparator = new Comparator('>=0.0.0') - } - high = high || comparator - low = low || comparator - if (gtfn(comparator.semver, high.semver, options)) { - high = comparator - } else if (ltfn(comparator.semver, low.semver, options)) { - low = comparator - } - }) - - // If the edge version comparator has a operator then our version - // isn't outside it - if (high.operator === comp || high.operator === ecomp) { - return false - } - - // If the lowest version comparator has an operator and our version - // is less than it then it isn't higher than the range - if ((!low.operator || low.operator === comp) && - ltefn(version, low.semver)) { - return false - } else if (low.operator === ecomp && ltfn(version, low.semver)) { - return false - } - } - return true -} - -module.exports = outside - - -/***/ }), - -/***/ 3117: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -// given a set of versions and a range, create a "simplified" range -// that includes the same versions that the original range does -// If the original range is shorter than the simplified one, return that. -const satisfies = __nccwpck_require__(3462) -const compare = __nccwpck_require__(8224) -module.exports = (versions, range, options) => { - const set = [] - let first = null - let prev = null - const v = versions.sort((a, b) => compare(a, b, options)) - for (const version of v) { - const included = satisfies(version, range, options) - if (included) { - prev = version - if (!first) { - first = version - } - } else { - if (prev) { - set.push([first, prev]) - } - prev = null - first = null - } - } - if (first) { - set.push([first, null]) - } - - const ranges = [] - for (const [min, max] of set) { - if (min === max) { - ranges.push(min) - } else if (!max && min === v[0]) { - ranges.push('*') - } else if (!max) { - ranges.push(`>=${min}`) - } else if (min === v[0]) { - ranges.push(`<=${max}`) - } else { - ranges.push(`${min} - ${max}`) - } - } - const simplified = ranges.join(' || ') - const original = typeof range.raw === 'string' ? range.raw : String(range) - return simplified.length < original.length ? simplified : range -} - - -/***/ }), - -/***/ 680: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Range = __nccwpck_require__(3892) -const Comparator = __nccwpck_require__(6688) -const { ANY } = Comparator -const satisfies = __nccwpck_require__(3462) -const compare = __nccwpck_require__(8224) - -// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff: -// - Every simple range `r1, r2, ...` is a null set, OR -// - Every simple range `r1, r2, ...` which is not a null set is a subset of -// some `R1, R2, ...` -// -// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff: -// - If c is only the ANY comparator -// - If C is only the ANY comparator, return true -// - Else if in prerelease mode, return false -// - else replace c with `[>=0.0.0]` -// - If C is only the ANY comparator -// - if in prerelease mode, return true -// - else replace C with `[>=0.0.0]` -// - Let EQ be the set of = comparators in c -// - If EQ is more than one, return true (null set) -// - Let GT be the highest > or >= comparator in c -// - Let LT be the lowest < or <= comparator in c -// - If GT and LT, and GT.semver > LT.semver, return true (null set) -// - If any C is a = range, and GT or LT are set, return false -// - If EQ -// - If GT, and EQ does not satisfy GT, return true (null set) -// - If LT, and EQ does not satisfy LT, return true (null set) -// - If EQ satisfies every C, return true -// - Else return false -// - If GT -// - If GT.semver is lower than any > or >= comp in C, return false -// - If GT is >=, and GT.semver does not satisfy every C, return false -// - If GT.semver has a prerelease, and not in prerelease mode -// - If no C has a prerelease and the GT.semver tuple, return false -// - If LT -// - If LT.semver is greater than any < or <= comp in C, return false -// - If LT is <=, and LT.semver does not satisfy every C, return false -// - If GT.semver has a prerelease, and not in prerelease mode -// - If no C has a prerelease and the LT.semver tuple, return false -// - Else return true - -const subset = (sub, dom, options = {}) => { - if (sub === dom) { - return true - } - - sub = new Range(sub, options) - dom = new Range(dom, options) - let sawNonNull = false - - OUTER: for (const simpleSub of sub.set) { - for (const simpleDom of dom.set) { - const isSub = simpleSubset(simpleSub, simpleDom, options) - sawNonNull = sawNonNull || isSub !== null - if (isSub) { - continue OUTER - } - } - // the null set is a subset of everything, but null simple ranges in - // a complex range should be ignored. so if we saw a non-null range, - // then we know this isn't a subset, but if EVERY simple range was null, - // then it is a subset. - if (sawNonNull) { - return false - } - } - return true -} - -const minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')] -const minimumVersion = [new Comparator('>=0.0.0')] - -const simpleSubset = (sub, dom, options) => { - if (sub === dom) { - return true - } - - if (sub.length === 1 && sub[0].semver === ANY) { - if (dom.length === 1 && dom[0].semver === ANY) { - return true - } else if (options.includePrerelease) { - sub = minimumVersionWithPreRelease - } else { - sub = minimumVersion - } - } - - if (dom.length === 1 && dom[0].semver === ANY) { - if (options.includePrerelease) { - return true - } else { - dom = minimumVersion - } - } - - const eqSet = new Set() - let gt, lt - for (const c of sub) { - if (c.operator === '>' || c.operator === '>=') { - gt = higherGT(gt, c, options) - } else if (c.operator === '<' || c.operator === '<=') { - lt = lowerLT(lt, c, options) - } else { - eqSet.add(c.semver) - } - } - - if (eqSet.size > 1) { - return null - } - - let gtltComp - if (gt && lt) { - gtltComp = compare(gt.semver, lt.semver, options) - if (gtltComp > 0) { - return null - } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) { - return null - } - } - - // will iterate one or zero times - for (const eq of eqSet) { - if (gt && !satisfies(eq, String(gt), options)) { - return null - } - - if (lt && !satisfies(eq, String(lt), options)) { - return null - } - - for (const c of dom) { - if (!satisfies(eq, String(c), options)) { - return false - } - } - - return true - } - - let higher, lower - let hasDomLT, hasDomGT - // if the subset has a prerelease, we need a comparator in the superset - // with the same tuple and a prerelease, or it's not a subset - let needDomLTPre = lt && - !options.includePrerelease && - lt.semver.prerelease.length ? lt.semver : false - let needDomGTPre = gt && - !options.includePrerelease && - gt.semver.prerelease.length ? gt.semver : false - // exception: <1.2.3-0 is the same as <1.2.3 - if (needDomLTPre && needDomLTPre.prerelease.length === 1 && - lt.operator === '<' && needDomLTPre.prerelease[0] === 0) { - needDomLTPre = false - } - - for (const c of dom) { - hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>=' - hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<=' - if (gt) { - if (needDomGTPre) { - if (c.semver.prerelease && c.semver.prerelease.length && - c.semver.major === needDomGTPre.major && - c.semver.minor === needDomGTPre.minor && - c.semver.patch === needDomGTPre.patch) { - needDomGTPre = false - } - } - if (c.operator === '>' || c.operator === '>=') { - higher = higherGT(gt, c, options) - if (higher === c && higher !== gt) { - return false - } - } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) { - return false - } - } - if (lt) { - if (needDomLTPre) { - if (c.semver.prerelease && c.semver.prerelease.length && - c.semver.major === needDomLTPre.major && - c.semver.minor === needDomLTPre.minor && - c.semver.patch === needDomLTPre.patch) { - needDomLTPre = false - } - } - if (c.operator === '<' || c.operator === '<=') { - lower = lowerLT(lt, c, options) - if (lower === c && lower !== lt) { - return false - } - } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) { - return false - } - } - if (!c.operator && (lt || gt) && gtltComp !== 0) { - return false - } - } - - // if there was a < or >, and nothing in the dom, then must be false - // UNLESS it was limited by another range in the other direction. - // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0 - if (gt && hasDomLT && !lt && gtltComp !== 0) { - return false - } - - if (lt && hasDomGT && !gt && gtltComp !== 0) { - return false - } - - // we needed a prerelease range in a specific tuple, but didn't get one - // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0, - // because it includes prereleases in the 1.2.3 tuple - if (needDomGTPre || needDomLTPre) { - return false - } - - return true -} - -// >=1.2.3 is lower than >1.2.3 -const higherGT = (a, b, options) => { - if (!a) { - return b - } - const comp = compare(a.semver, b.semver, options) - return comp > 0 ? a - : comp < 0 ? b - : b.operator === '>' && a.operator === '>=' ? b - : a -} - -// <=1.2.3 is higher than <1.2.3 -const lowerLT = (a, b, options) => { - if (!a) { - return b - } - const comp = compare(a.semver, b.semver, options) - return comp < 0 ? a - : comp > 0 ? b - : b.operator === '<' && a.operator === '<=' ? b - : a -} - -module.exports = subset - - -/***/ }), - -/***/ 4975: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Range = __nccwpck_require__(3892) - -// Mostly just for testing and legacy API reasons -const toComparators = (range, options) => - new Range(range, options).set - .map(comp => comp.map(c => c.value).join(' ').trim().split(' ')) - -module.exports = toComparators - - -/***/ }), - -/***/ 1106: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; - - -const Range = __nccwpck_require__(3892) -const validRange = (range, options) => { - try { - // Return '*' instead of '' so that truthiness works. - // This will throw if it's invalid anyway - return new Range(range, options).range || '*' - } catch (er) { - return null - } -} -module.exports = validRange - - /***/ }), /***/ 9379: @@ -10064,6 +7368,19 @@ class SemVer { module.exports = SemVer +/***/ }), + +/***/ 1799: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const parse = __nccwpck_require__(6353) +const clean = (version, options) => { + const s = parse(version.trim().replace(/^[=v]+/, ''), options) + return s ? s.version : null +} +module.exports = clean + + /***/ }), /***/ 8646: @@ -10190,6 +7507,30 @@ const coerce = (version, options) => { module.exports = coerce +/***/ }), + +/***/ 7648: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const compareBuild = (a, b, loose) => { + const versionA = new SemVer(a, loose) + const versionB = new SemVer(b, loose) + return versionA.compare(versionB) || versionA.compareBuild(versionB) +} +module.exports = compareBuild + + +/***/ }), + +/***/ 6874: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const compare = __nccwpck_require__(8469) +const compareLoose = (a, b) => compare(a, b, true) +module.exports = compareLoose + + /***/ }), /***/ 8469: @@ -10202,6 +7543,78 @@ const compare = (a, b, loose) => module.exports = compare +/***/ }), + +/***/ 711: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const parse = __nccwpck_require__(6353) + +const diff = (version1, version2) => { + const v1 = parse(version1, null, true) + const v2 = parse(version2, null, true) + const comparison = v1.compare(v2) + + if (comparison === 0) { + return null + } + + const v1Higher = comparison > 0 + const highVersion = v1Higher ? v1 : v2 + const lowVersion = v1Higher ? v2 : v1 + const highHasPre = !!highVersion.prerelease.length + const lowHasPre = !!lowVersion.prerelease.length + + if (lowHasPre && !highHasPre) { + // Going from prerelease -> no prerelease requires some special casing + + // If the low version has only a major, then it will always be a major + // Some examples: + // 1.0.0-1 -> 1.0.0 + // 1.0.0-1 -> 1.1.1 + // 1.0.0-1 -> 2.0.0 + if (!lowVersion.patch && !lowVersion.minor) { + return 'major' + } + + // Otherwise it can be determined by checking the high version + + if (highVersion.patch) { + // anything higher than a patch bump would result in the wrong version + return 'patch' + } + + if (highVersion.minor) { + // anything higher than a minor bump would result in the wrong version + return 'minor' + } + + // bumping major/minor/patch all have same result + return 'major' + } + + // add the `pre` prefix if we are going to a prerelease version + const prefix = highHasPre ? 'pre' : '' + + if (v1.major !== v2.major) { + return prefix + 'major' + } + + if (v1.minor !== v2.minor) { + return prefix + 'minor' + } + + if (v1.patch !== v2.patch) { + return prefix + 'patch' + } + + // high and low are preleases + return 'prerelease' +} + +module.exports = diff + + /***/ }), /***/ 5082: @@ -10232,6 +7645,32 @@ const gte = (a, b, loose) => compare(a, b, loose) >= 0 module.exports = gte +/***/ }), + +/***/ 2338: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) + +const inc = (version, release, options, identifier, identifierBase) => { + if (typeof (options) === 'string') { + identifierBase = identifier + identifier = options + options = undefined + } + + try { + return new SemVer( + version instanceof SemVer ? version.version : version, + options + ).inc(release, identifier, identifierBase).version + } catch (er) { + return null + } +} +module.exports = inc + + /***/ }), /***/ 3872: @@ -10252,6 +7691,26 @@ const lte = (a, b, loose) => compare(a, b, loose) <= 0 module.exports = lte +/***/ }), + +/***/ 8511: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const major = (a, loose) => new SemVer(a, loose).major +module.exports = major + + +/***/ }), + +/***/ 2603: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const minor = (a, loose) => new SemVer(a, loose).minor +module.exports = minor + + /***/ }), /***/ 4974: @@ -10285,6 +7744,49 @@ const parse = (version, options, throwErrors = false) => { module.exports = parse +/***/ }), + +/***/ 8756: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const patch = (a, loose) => new SemVer(a, loose).patch +module.exports = patch + + +/***/ }), + +/***/ 5714: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const parse = __nccwpck_require__(6353) +const prerelease = (version, options) => { + const parsed = parse(version, options) + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null +} +module.exports = prerelease + + +/***/ }), + +/***/ 2173: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const compare = __nccwpck_require__(8469) +const rcompare = (a, b, loose) => compare(b, a, loose) +module.exports = rcompare + + +/***/ }), + +/***/ 7192: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const compareBuild = __nccwpck_require__(7648) +const rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose)) +module.exports = rsort + + /***/ }), /***/ 8011: @@ -10302,6 +7804,125 @@ const satisfies = (version, range, options) => { module.exports = satisfies +/***/ }), + +/***/ 9872: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const compareBuild = __nccwpck_require__(7648) +const sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose)) +module.exports = sort + + +/***/ }), + +/***/ 8780: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const parse = __nccwpck_require__(6353) +const valid = (version, options) => { + const v = parse(version, options) + return v ? v.version : null +} +module.exports = valid + + +/***/ }), + +/***/ 2088: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +// just pre-load all the stuff that index.js lazily exports +const internalRe = __nccwpck_require__(5471) +const constants = __nccwpck_require__(5101) +const SemVer = __nccwpck_require__(7163) +const identifiers = __nccwpck_require__(3348) +const parse = __nccwpck_require__(6353) +const valid = __nccwpck_require__(8780) +const clean = __nccwpck_require__(1799) +const inc = __nccwpck_require__(2338) +const diff = __nccwpck_require__(711) +const major = __nccwpck_require__(8511) +const minor = __nccwpck_require__(2603) +const patch = __nccwpck_require__(8756) +const prerelease = __nccwpck_require__(5714) +const compare = __nccwpck_require__(8469) +const rcompare = __nccwpck_require__(2173) +const compareLoose = __nccwpck_require__(6874) +const compareBuild = __nccwpck_require__(7648) +const sort = __nccwpck_require__(9872) +const rsort = __nccwpck_require__(7192) +const gt = __nccwpck_require__(6599) +const lt = __nccwpck_require__(3872) +const eq = __nccwpck_require__(5082) +const neq = __nccwpck_require__(4974) +const gte = __nccwpck_require__(1236) +const lte = __nccwpck_require__(6717) +const cmp = __nccwpck_require__(8646) +const coerce = __nccwpck_require__(5385) +const Comparator = __nccwpck_require__(9379) +const Range = __nccwpck_require__(6782) +const satisfies = __nccwpck_require__(8011) +const toComparators = __nccwpck_require__(4750) +const maxSatisfying = __nccwpck_require__(5574) +const minSatisfying = __nccwpck_require__(8595) +const minVersion = __nccwpck_require__(1866) +const validRange = __nccwpck_require__(4737) +const outside = __nccwpck_require__(280) +const gtr = __nccwpck_require__(2276) +const ltr = __nccwpck_require__(5213) +const intersects = __nccwpck_require__(3465) +const simplifyRange = __nccwpck_require__(2028) +const subset = __nccwpck_require__(1489) +module.exports = { + parse, + valid, + clean, + inc, + diff, + major, + minor, + patch, + prerelease, + compare, + rcompare, + compareLoose, + compareBuild, + sort, + rsort, + gt, + lt, + eq, + neq, + gte, + lte, + cmp, + coerce, + Comparator, + Range, + satisfies, + toComparators, + maxSatisfying, + minSatisfying, + minVersion, + validRange, + outside, + gtr, + ltr, + intersects, + simplifyRange, + subset, + SemVer, + re: internalRe.re, + src: internalRe.src, + tokens: internalRe.t, + SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION, + RELEASE_TYPES: constants.RELEASE_TYPES, + compareIdentifiers: identifiers.compareIdentifiers, + rcompareIdentifiers: identifiers.rcompareIdentifiers, +} + + /***/ }), /***/ 5101: @@ -10683,6 +8304,601 @@ createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$') createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$') +/***/ }), + +/***/ 2276: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +// Determine if version is greater than all the versions possible in the range. +const outside = __nccwpck_require__(280) +const gtr = (version, range, options) => outside(version, range, '>', options) +module.exports = gtr + + +/***/ }), + +/***/ 3465: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const Range = __nccwpck_require__(6782) +const intersects = (r1, r2, options) => { + r1 = new Range(r1, options) + r2 = new Range(r2, options) + return r1.intersects(r2, options) +} +module.exports = intersects + + +/***/ }), + +/***/ 5213: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const outside = __nccwpck_require__(280) +// Determine if version is less than all the versions possible in the range +const ltr = (version, range, options) => outside(version, range, '<', options) +module.exports = ltr + + +/***/ }), + +/***/ 5574: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const Range = __nccwpck_require__(6782) + +const maxSatisfying = (versions, range, options) => { + let max = null + let maxSV = null + let rangeObj = null + try { + rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach((v) => { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v + maxSV = new SemVer(max, options) + } + } + }) + return max +} +module.exports = maxSatisfying + + +/***/ }), + +/***/ 8595: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const Range = __nccwpck_require__(6782) +const minSatisfying = (versions, range, options) => { + let min = null + let minSV = null + let rangeObj = null + try { + rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach((v) => { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v + minSV = new SemVer(min, options) + } + } + }) + return min +} +module.exports = minSatisfying + + +/***/ }), + +/***/ 1866: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const Range = __nccwpck_require__(6782) +const gt = __nccwpck_require__(6599) + +const minVersion = (range, loose) => { + range = new Range(range, loose) + + let minver = new SemVer('0.0.0') + if (range.test(minver)) { + return minver + } + + minver = new SemVer('0.0.0-0') + if (range.test(minver)) { + return minver + } + + minver = null + for (let i = 0; i < range.set.length; ++i) { + const comparators = range.set[i] + + let setMin = null + comparators.forEach((comparator) => { + // Clone to avoid manipulating the comparator's semver object. + const compver = new SemVer(comparator.semver.version) + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++ + } else { + compver.prerelease.push(0) + } + compver.raw = compver.format() + /* fallthrough */ + case '': + case '>=': + if (!setMin || gt(compver, setMin)) { + setMin = compver + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error(`Unexpected operation: ${comparator.operator}`) + } + }) + if (setMin && (!minver || gt(minver, setMin))) { + minver = setMin + } + } + + if (minver && range.test(minver)) { + return minver + } + + return null +} +module.exports = minVersion + + +/***/ }), + +/***/ 280: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const SemVer = __nccwpck_require__(7163) +const Comparator = __nccwpck_require__(9379) +const { ANY } = Comparator +const Range = __nccwpck_require__(6782) +const satisfies = __nccwpck_require__(8011) +const gt = __nccwpck_require__(6599) +const lt = __nccwpck_require__(3872) +const lte = __nccwpck_require__(6717) +const gte = __nccwpck_require__(1236) + +const outside = (version, range, hilo, options) => { + version = new SemVer(version, options) + range = new Range(range, options) + + let gtfn, ltefn, ltfn, comp, ecomp + switch (hilo) { + case '>': + gtfn = gt + ltefn = lte + ltfn = lt + comp = '>' + ecomp = '>=' + break + case '<': + gtfn = lt + ltefn = gte + ltfn = gt + comp = '<' + ecomp = '<=' + break + default: + throw new TypeError('Must provide a hilo val of "<" or ">"') + } + + // If it satisfies the range it is not outside + if (satisfies(version, range, options)) { + return false + } + + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (let i = 0; i < range.set.length; ++i) { + const comparators = range.set[i] + + let high = null + let low = null + + comparators.forEach((comparator) => { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator + low = low || comparator + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator + } + }) + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false + } + + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false + } + } + return true +} + +module.exports = outside + + +/***/ }), + +/***/ 2028: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +// given a set of versions and a range, create a "simplified" range +// that includes the same versions that the original range does +// If the original range is shorter than the simplified one, return that. +const satisfies = __nccwpck_require__(8011) +const compare = __nccwpck_require__(8469) +module.exports = (versions, range, options) => { + const set = [] + let first = null + let prev = null + const v = versions.sort((a, b) => compare(a, b, options)) + for (const version of v) { + const included = satisfies(version, range, options) + if (included) { + prev = version + if (!first) { + first = version + } + } else { + if (prev) { + set.push([first, prev]) + } + prev = null + first = null + } + } + if (first) { + set.push([first, null]) + } + + const ranges = [] + for (const [min, max] of set) { + if (min === max) { + ranges.push(min) + } else if (!max && min === v[0]) { + ranges.push('*') + } else if (!max) { + ranges.push(`>=${min}`) + } else if (min === v[0]) { + ranges.push(`<=${max}`) + } else { + ranges.push(`${min} - ${max}`) + } + } + const simplified = ranges.join(' || ') + const original = typeof range.raw === 'string' ? range.raw : String(range) + return simplified.length < original.length ? simplified : range +} + + +/***/ }), + +/***/ 1489: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const Range = __nccwpck_require__(6782) +const Comparator = __nccwpck_require__(9379) +const { ANY } = Comparator +const satisfies = __nccwpck_require__(8011) +const compare = __nccwpck_require__(8469) + +// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff: +// - Every simple range `r1, r2, ...` is a null set, OR +// - Every simple range `r1, r2, ...` which is not a null set is a subset of +// some `R1, R2, ...` +// +// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff: +// - If c is only the ANY comparator +// - If C is only the ANY comparator, return true +// - Else if in prerelease mode, return false +// - else replace c with `[>=0.0.0]` +// - If C is only the ANY comparator +// - if in prerelease mode, return true +// - else replace C with `[>=0.0.0]` +// - Let EQ be the set of = comparators in c +// - If EQ is more than one, return true (null set) +// - Let GT be the highest > or >= comparator in c +// - Let LT be the lowest < or <= comparator in c +// - If GT and LT, and GT.semver > LT.semver, return true (null set) +// - If any C is a = range, and GT or LT are set, return false +// - If EQ +// - If GT, and EQ does not satisfy GT, return true (null set) +// - If LT, and EQ does not satisfy LT, return true (null set) +// - If EQ satisfies every C, return true +// - Else return false +// - If GT +// - If GT.semver is lower than any > or >= comp in C, return false +// - If GT is >=, and GT.semver does not satisfy every C, return false +// - If GT.semver has a prerelease, and not in prerelease mode +// - If no C has a prerelease and the GT.semver tuple, return false +// - If LT +// - If LT.semver is greater than any < or <= comp in C, return false +// - If LT is <=, and LT.semver does not satisfy every C, return false +// - If GT.semver has a prerelease, and not in prerelease mode +// - If no C has a prerelease and the LT.semver tuple, return false +// - Else return true + +const subset = (sub, dom, options = {}) => { + if (sub === dom) { + return true + } + + sub = new Range(sub, options) + dom = new Range(dom, options) + let sawNonNull = false + + OUTER: for (const simpleSub of sub.set) { + for (const simpleDom of dom.set) { + const isSub = simpleSubset(simpleSub, simpleDom, options) + sawNonNull = sawNonNull || isSub !== null + if (isSub) { + continue OUTER + } + } + // the null set is a subset of everything, but null simple ranges in + // a complex range should be ignored. so if we saw a non-null range, + // then we know this isn't a subset, but if EVERY simple range was null, + // then it is a subset. + if (sawNonNull) { + return false + } + } + return true +} + +const minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')] +const minimumVersion = [new Comparator('>=0.0.0')] + +const simpleSubset = (sub, dom, options) => { + if (sub === dom) { + return true + } + + if (sub.length === 1 && sub[0].semver === ANY) { + if (dom.length === 1 && dom[0].semver === ANY) { + return true + } else if (options.includePrerelease) { + sub = minimumVersionWithPreRelease + } else { + sub = minimumVersion + } + } + + if (dom.length === 1 && dom[0].semver === ANY) { + if (options.includePrerelease) { + return true + } else { + dom = minimumVersion + } + } + + const eqSet = new Set() + let gt, lt + for (const c of sub) { + if (c.operator === '>' || c.operator === '>=') { + gt = higherGT(gt, c, options) + } else if (c.operator === '<' || c.operator === '<=') { + lt = lowerLT(lt, c, options) + } else { + eqSet.add(c.semver) + } + } + + if (eqSet.size > 1) { + return null + } + + let gtltComp + if (gt && lt) { + gtltComp = compare(gt.semver, lt.semver, options) + if (gtltComp > 0) { + return null + } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) { + return null + } + } + + // will iterate one or zero times + for (const eq of eqSet) { + if (gt && !satisfies(eq, String(gt), options)) { + return null + } + + if (lt && !satisfies(eq, String(lt), options)) { + return null + } + + for (const c of dom) { + if (!satisfies(eq, String(c), options)) { + return false + } + } + + return true + } + + let higher, lower + let hasDomLT, hasDomGT + // if the subset has a prerelease, we need a comparator in the superset + // with the same tuple and a prerelease, or it's not a subset + let needDomLTPre = lt && + !options.includePrerelease && + lt.semver.prerelease.length ? lt.semver : false + let needDomGTPre = gt && + !options.includePrerelease && + gt.semver.prerelease.length ? gt.semver : false + // exception: <1.2.3-0 is the same as <1.2.3 + if (needDomLTPre && needDomLTPre.prerelease.length === 1 && + lt.operator === '<' && needDomLTPre.prerelease[0] === 0) { + needDomLTPre = false + } + + for (const c of dom) { + hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>=' + hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<=' + if (gt) { + if (needDomGTPre) { + if (c.semver.prerelease && c.semver.prerelease.length && + c.semver.major === needDomGTPre.major && + c.semver.minor === needDomGTPre.minor && + c.semver.patch === needDomGTPre.patch) { + needDomGTPre = false + } + } + if (c.operator === '>' || c.operator === '>=') { + higher = higherGT(gt, c, options) + if (higher === c && higher !== gt) { + return false + } + } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) { + return false + } + } + if (lt) { + if (needDomLTPre) { + if (c.semver.prerelease && c.semver.prerelease.length && + c.semver.major === needDomLTPre.major && + c.semver.minor === needDomLTPre.minor && + c.semver.patch === needDomLTPre.patch) { + needDomLTPre = false + } + } + if (c.operator === '<' || c.operator === '<=') { + lower = lowerLT(lt, c, options) + if (lower === c && lower !== lt) { + return false + } + } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) { + return false + } + } + if (!c.operator && (lt || gt) && gtltComp !== 0) { + return false + } + } + + // if there was a < or >, and nothing in the dom, then must be false + // UNLESS it was limited by another range in the other direction. + // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0 + if (gt && hasDomLT && !lt && gtltComp !== 0) { + return false + } + + if (lt && hasDomGT && !gt && gtltComp !== 0) { + return false + } + + // we needed a prerelease range in a specific tuple, but didn't get one + // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0, + // because it includes prereleases in the 1.2.3 tuple + if (needDomGTPre || needDomLTPre) { + return false + } + + return true +} + +// >=1.2.3 is lower than >1.2.3 +const higherGT = (a, b, options) => { + if (!a) { + return b + } + const comp = compare(a.semver, b.semver, options) + return comp > 0 ? a + : comp < 0 ? b + : b.operator === '>' && a.operator === '>=' ? b + : a +} + +// <=1.2.3 is higher than <1.2.3 +const lowerLT = (a, b, options) => { + if (!a) { + return b + } + const comp = compare(a.semver, b.semver, options) + return comp < 0 ? a + : comp > 0 ? b + : b.operator === '<' && a.operator === '<=' ? b + : a +} + +module.exports = subset + + +/***/ }), + +/***/ 4750: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const Range = __nccwpck_require__(6782) + +// Mostly just for testing and legacy API reasons +const toComparators = (range, options) => + new Range(range, options).set + .map(comp => comp.map(c => c.value).join(' ').trim().split(' ')) + +module.exports = toComparators + + +/***/ }), + +/***/ 4737: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +const Range = __nccwpck_require__(6782) +const validRange = (range, options) => { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, options).range || '*' + } catch (er) { + return null + } +} +module.exports = validRange + + /***/ }), /***/ 770: @@ -35004,544 +33220,6 @@ function parseParams (str) { module.exports = parseParams -/***/ }), - -/***/ 8733: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.CliInstaller = exports.cliUrlBuilder = exports.archMap = void 0; -const os_1 = __importDefault(__nccwpck_require__(857)); -const core = __importStar(__nccwpck_require__(7484)); -const tc = __importStar(__nccwpck_require__(3472)); -// maps OS architecture names to 1Password CLI installer architecture names -exports.archMap = { - ia32: "386", - x64: "amd64", - arm: "arm", - arm64: "arm64", -}; -// Builds the download URL for the 1Password CLI based on the platform and version. -exports.cliUrlBuilder = { - linux: (version, arch) => `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_linux_${arch}_${version}.zip`, - darwin: (version) => `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_apple_universal_${version}.pkg`, - win32: (version, arch) => `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_windows_${arch}_${version}.zip`, -}; -class CliInstaller { - version; - arch; - constructor(version) { - this.version = version; - this.arch = this.getArch(); - } - async install(url) { - console.info(`Downloading 1Password CLI from: ${url}`); - const downloadPath = await tc.downloadTool(url); - console.info("Installing 1Password CLI"); - const extractedPath = await tc.extractZip(downloadPath); - core.addPath(extractedPath); - core.info("1Password CLI installed"); - } - getArch() { - const arch = exports.archMap[os_1.default.arch()]; - if (!arch) { - throw new Error("Unsupported architecture"); - } - return arch; - } -} -exports.CliInstaller = CliInstaller; - - -/***/ }), - -/***/ 2846: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.newCliInstaller = void 0; -var installer_1 = __nccwpck_require__(3074); -Object.defineProperty(exports, "newCliInstaller", ({ enumerable: true, get: function () { return installer_1.newCliInstaller; } })); - - -/***/ }), - -/***/ 3074: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.newCliInstaller = void 0; -const os_1 = __importDefault(__nccwpck_require__(857)); -const linux_1 = __nccwpck_require__(2500); -const macos_1 = __nccwpck_require__(5315); -const windows_1 = __nccwpck_require__(2403); -const newCliInstaller = (version) => { - const platform = os_1.default.platform(); - switch (platform) { - case "linux": - return new linux_1.LinuxInstaller(version); - case "darwin": - return new macos_1.MacOsInstaller(version); - case "win32": - return new windows_1.WindowsInstaller(version); - default: - throw new Error(`Unsupported platform: ${platform}`); - } -}; -exports.newCliInstaller = newCliInstaller; - - -/***/ }), - -/***/ 2500: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.LinuxInstaller = void 0; -const cli_installer_1 = __nccwpck_require__(8733); -class LinuxInstaller extends cli_installer_1.CliInstaller { - platform = "linux"; // Node.js platform identifier for Linux - constructor(version) { - super(version); - } - async installCli() { - const urlBuilder = cli_installer_1.cliUrlBuilder[this.platform]; - await super.install(urlBuilder(this.version, this.arch)); - } -} -exports.LinuxInstaller = LinuxInstaller; - - -/***/ }), - -/***/ 5315: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.MacOsInstaller = void 0; -const child_process_1 = __nccwpck_require__(5317); -const fs = __importStar(__nccwpck_require__(9896)); -const path = __importStar(__nccwpck_require__(6928)); -const util_1 = __nccwpck_require__(9023); -const core = __importStar(__nccwpck_require__(7484)); -const tc = __importStar(__nccwpck_require__(3472)); -const cli_installer_1 = __nccwpck_require__(8733); -const execAsync = (0, util_1.promisify)(child_process_1.exec); -class MacOsInstaller extends cli_installer_1.CliInstaller { - platform = "darwin"; // Node.js platform identifier for macOS - constructor(version) { - super(version); - } - async installCli() { - const urlBuilder = cli_installer_1.cliUrlBuilder[this.platform]; - await this.install(urlBuilder(this.version)); - } - // @actions/tool-cache package does not support .pkg files, so we need to handle the installation manually - async install(downloadUrl) { - console.info(`Downloading 1Password CLI from: ${downloadUrl}`); - const pkgPath = await tc.downloadTool(downloadUrl); - const pkgWithExtension = `${pkgPath}.pkg`; - fs.renameSync(pkgPath, pkgWithExtension); - const expandDir = "temp-pkg"; - await execAsync(`pkgutil --expand "${pkgWithExtension}" "${expandDir}"`); - const payloadPath = path.join(expandDir, "op.pkg", "Payload"); - console.info("Installing 1Password CLI"); - const cliPath = await tc.extractTar(payloadPath); - core.addPath(cliPath); - fs.rmSync(expandDir, { recursive: true, force: true }); - fs.rmSync(pkgPath, { force: true }); - core.info("1Password CLI installed"); - } -} -exports.MacOsInstaller = MacOsInstaller; - - -/***/ }), - -/***/ 2403: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.WindowsInstaller = void 0; -const cli_installer_1 = __nccwpck_require__(8733); -class WindowsInstaller extends cli_installer_1.CliInstaller { - platform = "win32"; // Node.js platform identifier for Windows - constructor(version) { - super(version); - } - async installCli() { - const urlBuilder = cli_installer_1.cliUrlBuilder[this.platform]; - await super.install(urlBuilder(this.version, this.arch)); - } -} -exports.WindowsInstaller = WindowsInstaller; - - -/***/ }), - -/***/ 9046: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.installCliOnGithubActionRunner = void 0; -const core = __importStar(__nccwpck_require__(7484)); -const version_1 = __nccwpck_require__(8950); -const cli_installer_1 = __nccwpck_require__(2846); -// Installs the 1Password CLI on a GitHub Action runner. -const installCliOnGithubActionRunner = async (version) => { - // Get the version from parameter, if not passed - from the job input. Defaults to latest if no version is provided - const providedVersion = version || core.getInput("version") || version_1.ReleaseChannel.latest; - const versionResolver = new version_1.VersionResolver(providedVersion); - await versionResolver.resolve(); - const installer = (0, cli_installer_1.newCliInstaller)(versionResolver.get()); - await installer.installCli(); -}; -exports.installCliOnGithubActionRunner = installCliOnGithubActionRunner; - - -/***/ }), - -/***/ 1621: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; -var __webpack_unused_export__; - -__webpack_unused_export__ = ({ value: true }); -__webpack_unused_export__ = __webpack_unused_export__ = exports.Cq = void 0; -var github_action_1 = __nccwpck_require__(9046); -Object.defineProperty(exports, "Cq", ({ enumerable: true, get: function () { return github_action_1.installCliOnGithubActionRunner; } })); -var version_1 = __nccwpck_require__(8950); -__webpack_unused_export__ = ({ enumerable: true, get: function () { return version_1.ReleaseChannel; } }); -__webpack_unused_export__ = ({ enumerable: true, get: function () { return version_1.VersionResolver; } }); - - -/***/ }), - -/***/ 4823: -/***/ ((__unused_webpack_module, exports) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.ReleaseChannel = void 0; -var ReleaseChannel; -(function (ReleaseChannel) { - ReleaseChannel["latest"] = "latest"; - ReleaseChannel["latestBeta"] = "latest-beta"; -})(ReleaseChannel || (exports.ReleaseChannel = ReleaseChannel = {})); - - -/***/ }), - -/***/ 1592: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getLatestVersion = void 0; -const core = __importStar(__nccwpck_require__(7484)); -const constants_1 = __nccwpck_require__(4823); -// Returns the latest version of the 1Password CLI based on the specified channel. -const getLatestVersion = async (channel) => { - core.info(`Getting ${channel} version number`); - const res = await fetch("https://app-updates.agilebits.com/latest"); - const json = (await res.json()); - const latestStable = json?.CLI2?.release?.version; - const latestBeta = json?.CLI2?.beta?.version; - const version = channel === constants_1.ReleaseChannel.latestBeta ? latestBeta : latestStable; - if (!version) { - core.error(`No ${channel} versions found`); - throw new Error(`No ${channel} versions found`); - } - return version; -}; -exports.getLatestVersion = getLatestVersion; - - -/***/ }), - -/***/ 8950: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { - -"use strict"; - -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.ReleaseChannel = exports.VersionResolver = void 0; -var version_resolver_1 = __nccwpck_require__(609); -Object.defineProperty(exports, "VersionResolver", ({ enumerable: true, get: function () { return version_resolver_1.VersionResolver; } })); -var constants_1 = __nccwpck_require__(4823); -Object.defineProperty(exports, "ReleaseChannel", ({ enumerable: true, get: function () { return constants_1.ReleaseChannel; } })); - - -/***/ }), - -/***/ 2946: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.validateVersion = void 0; -const semver_1 = __importDefault(__nccwpck_require__(3781)); -const constants_1 = __nccwpck_require__(4823); -// Validates if the provided version type is a valid enum value or a valid semver version. -const validateVersion = (input) => { - if (Object.values(constants_1.ReleaseChannel).includes(input)) { - return; - } - // 1Password beta releases (aka 2.19.0-beta.01) are not semver compliant. - // According to semver, it should be "2.19.0-beta.1". - // That's why we need to normalize them before validating. - // Accepts valid semver versions like "2.18.0" or beta-releases like "2.19.0-beta.01" - // or versions with 'v' prefix like "v2.19.0" - const normalized = input.replace(/-beta\.0*(\d+)/, "-beta.$1"); - const normInput = new semver_1.default.SemVer(normalized); - if (semver_1.default.valid(normInput)) { - return; - } - throw new Error(`Invalid version input: ${input}`); -}; -exports.validateVersion = validateVersion; - - -/***/ }), - -/***/ 609: -/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { - -"use strict"; - -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.VersionResolver = void 0; -const core = __importStar(__nccwpck_require__(7484)); -const constants_1 = __nccwpck_require__(4823); -const helper_1 = __nccwpck_require__(1592); -const validate_1 = __nccwpck_require__(2946); -class VersionResolver { - version; - constructor(version) { - this.validate(version); - this.version = version; - } - get() { - return this.version; - } - async resolve() { - core.info(`Resolving version: ${this.version}`); - if (!this.version) { - core.error("Version is not provided"); - throw new Error("Version is not provided"); - } - if (this.isReleaseChannel(this.version)) { - this.version = await (0, helper_1.getLatestVersion)(this.version); - } - // add `v` prefix if not already present - this.version = this.version.startsWith("v") - ? this.version - : `v${this.version}`; - } - validate(version) { - core.info(`Validating version number: '${version}'`); - (0, validate_1.validateVersion)(version); - core.info(`Version number '${version}' is valid`); - } - isReleaseChannel(value) { - return Object.values(constants_1.ReleaseChannel).includes(value); - } -} -exports.VersionResolver = VersionResolver; - - /***/ }), /***/ 8338: @@ -35632,15 +33310,261 @@ var __webpack_exports__ = {}; (() => { "use strict"; +// EXTERNAL MODULE: ./node_modules/dotenv/lib/main.js +var main = __nccwpck_require__(8889); +var main_default = /*#__PURE__*/__nccwpck_require__.n(main); // EXTERNAL MODULE: ./node_modules/@actions/core/lib/core.js var core = __nccwpck_require__(7484); // EXTERNAL MODULE: ./node_modules/@1password/op-js/dist/index.js var dist = __nccwpck_require__(7521); -// EXTERNAL MODULE: ./node_modules/op-cli-installer/dist/index.js -var op_cli_installer_dist = __nccwpck_require__(1621); -// EXTERNAL MODULE: ./node_modules/dotenv/lib/main.js -var main = __nccwpck_require__(8889); -var main_default = /*#__PURE__*/__nccwpck_require__.n(main); +;// CONCATENATED MODULE: ./src/op-cli-installer/version/constants.ts +var ReleaseChannel; +(function (ReleaseChannel) { + ReleaseChannel["latest"] = "latest"; + ReleaseChannel["latestBeta"] = "latest-beta"; +})(ReleaseChannel || (ReleaseChannel = {})); + +;// CONCATENATED MODULE: ./src/op-cli-installer/version/helper.ts + + +// Returns the latest version of the 1Password CLI based on the specified channel. +const getLatestVersion = async (channel) => { + core.info(`Getting ${channel} version number`); + const res = await fetch("https://app-updates.agilebits.com/latest"); + const json = (await res.json()); + const latestStable = json?.CLI2?.release?.version; + const latestBeta = json?.CLI2?.beta?.version; + const version = channel === ReleaseChannel.latestBeta ? latestBeta : latestStable; + if (!version) { + core.error(`No ${channel} versions found`); + throw new Error(`No ${channel} versions found`); + } + return version; +}; + +// EXTERNAL MODULE: ./node_modules/semver/index.js +var semver = __nccwpck_require__(2088); +var semver_default = /*#__PURE__*/__nccwpck_require__.n(semver); +;// CONCATENATED MODULE: ./src/op-cli-installer/version/validate.ts + + +// Validates if the provided version type is a valid enum value or a valid semver version. +const validateVersion = (input) => { + if (Object.values(ReleaseChannel).includes(input)) { + return; + } + // 1Password beta releases (aka 2.19.0-beta.01) are not semver compliant. + // According to semver, it should be "2.19.0-beta.1". + // That's why we need to normalize them before validating. + // Accepts valid semver versions like "2.18.0" or beta-releases like "2.19.0-beta.01" + // or versions with 'v' prefix like "v2.19.0" + const normalized = input.replace(/-beta\.0*(\d+)/, "-beta.$1"); + const normInput = new (semver_default()).SemVer(normalized); + if (semver_default().valid(normInput)) { + return; + } + throw new Error(`Invalid version input: ${input}`); +}; + +;// CONCATENATED MODULE: ./src/op-cli-installer/version/version-resolver.ts + + + + +class VersionResolver { + version; + constructor(version) { + this.validate(version); + this.version = version; + } + get() { + return this.version; + } + async resolve() { + core.info(`Resolving version: ${this.version}`); + if (!this.version) { + core.error("Version is not provided"); + throw new Error("Version is not provided"); + } + if (this.isReleaseChannel(this.version)) { + this.version = await getLatestVersion(this.version); + } + // add `v` prefix if not already present + this.version = this.version.startsWith("v") + ? this.version + : `v${this.version}`; + } + validate(version) { + core.info(`Validating version number: '${version}'`); + validateVersion(version); + core.info(`Version number '${version}' is valid`); + } + isReleaseChannel(value) { + return Object.values(ReleaseChannel).includes(value); + } +} + +;// CONCATENATED MODULE: ./src/op-cli-installer/version/index.ts + + + +// EXTERNAL MODULE: external "os" +var external_os_ = __nccwpck_require__(857); +var external_os_default = /*#__PURE__*/__nccwpck_require__.n(external_os_); +// EXTERNAL MODULE: ./node_modules/@actions/tool-cache/lib/tool-cache.js +var tool_cache = __nccwpck_require__(3472); +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/cli-installer/cli-installer.ts + + + +// maps OS architecture names to 1Password CLI installer architecture names +const archMap = { + ia32: "386", + x64: "amd64", + arm: "arm", + arm64: "arm64", +}; +// Builds the download URL for the 1Password CLI based on the platform and version. +const cliUrlBuilder = { + linux: (version, arch) => `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_linux_${arch}_${version}.zip`, + darwin: (version) => `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_apple_universal_${version}.pkg`, + win32: (version, arch) => `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_windows_${arch}_${version}.zip`, +}; +class CliInstaller { + version; + arch; + constructor(version) { + this.version = version; + this.arch = this.getArch(); + } + async install(url) { + console.info(`Downloading 1Password CLI from: ${url}`); + const downloadPath = await tool_cache.downloadTool(url); + console.info("Installing 1Password CLI"); + const extractedPath = await tool_cache.extractZip(downloadPath); + core.addPath(extractedPath); + core.info("1Password CLI installed"); + } + getArch() { + const arch = archMap[external_os_default().arch()]; + if (!arch) { + throw new Error("Unsupported architecture"); + } + return arch; + } +} + +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/cli-installer/linux.ts + +class LinuxInstaller extends CliInstaller { + platform = "linux"; // Node.js platform identifier for Linux + constructor(version) { + super(version); + } + async installCli() { + const urlBuilder = cliUrlBuilder[this.platform]; + await super.install(urlBuilder(this.version, this.arch)); + } +} + +// EXTERNAL MODULE: external "child_process" +var external_child_process_ = __nccwpck_require__(5317); +// EXTERNAL MODULE: external "fs" +var external_fs_ = __nccwpck_require__(9896); +// EXTERNAL MODULE: external "path" +var external_path_ = __nccwpck_require__(6928); +// EXTERNAL MODULE: external "util" +var external_util_ = __nccwpck_require__(9023); +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/cli-installer/macos.ts + + + + + + + + +const execFileAsync = (0,external_util_.promisify)(external_child_process_.execFile); +class MacOsInstaller extends CliInstaller { + platform = "darwin"; // Node.js platform identifier for macOS + constructor(version) { + super(version); + } + async installCli() { + const urlBuilder = cliUrlBuilder[this.platform]; + await this.install(urlBuilder(this.version)); + } + // @actions/tool-cache package does not support .pkg files, so we need to handle the installation manually + async install(downloadUrl) { + console.info(`Downloading 1Password CLI from: ${downloadUrl}`); + const pkgPath = await tool_cache.downloadTool(downloadUrl); + const pkgWithExtension = `${pkgPath}.pkg`; + external_fs_.renameSync(pkgPath, pkgWithExtension); + const expandDir = "temp-pkg"; + await execFileAsync("pkgutil", ["--expand", pkgWithExtension, expandDir]); + const payloadPath = external_path_.join(expandDir, "op.pkg", "Payload"); + console.info("Installing 1Password CLI"); + const cliPath = await tool_cache.extractTar(payloadPath); + core.addPath(cliPath); + external_fs_.rmSync(expandDir, { recursive: true, force: true }); + external_fs_.rmSync(pkgPath, { force: true }); + core.info("1Password CLI installed"); + } +} + +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/cli-installer/windows.ts + +class WindowsInstaller extends CliInstaller { + platform = "win32"; // Node.js platform identifier for Windows + constructor(version) { + super(version); + } + async installCli() { + const urlBuilder = cliUrlBuilder[this.platform]; + await super.install(urlBuilder(this.version, this.arch)); + } +} + +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/cli-installer/installer.ts + + + + +const newCliInstaller = (version) => { + const platform = external_os_default().platform(); + switch (platform) { + case "linux": + return new LinuxInstaller(version); + case "darwin": + return new MacOsInstaller(version); + case "win32": + return new WindowsInstaller(version); + default: + throw new Error(`Unsupported platform: ${platform}`); + } +}; + +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/cli-installer/index.ts + + +;// CONCATENATED MODULE: ./src/op-cli-installer/github-action/index.ts + + + +// Installs the 1Password CLI on a GitHub Action runner. +const installCliOnGithubActionRunner = async (version) => { + // Get the version from parameter, if not passed - from the job input. Defaults to latest if no version is provided + const providedVersion = version || core.getInput("version") || ReleaseChannel.latest; + const versionResolver = new VersionResolver(providedVersion); + await versionResolver.resolve(); + const installer = newCliInstaller(versionResolver.get()); + await installer.installCli(); +}; + +;// CONCATENATED MODULE: ./src/op-cli-installer/index.ts + + + // EXTERNAL MODULE: ./node_modules/@actions/exec/lib/exec.js var exec = __nccwpck_require__(5236); ;// CONCATENATED MODULE: ./package.json @@ -35773,7 +33697,7 @@ const installCLI = async () => { // If there's no CLI installed, then validateCli will throw an error, which we will use // as an indicator that we need to execute the installation script. await (0,dist.validateCli)().catch(async () => { - await (0,op_cli_installer_dist/* installCliOnGithubActionRunner */.Cq)(); + await installCliOnGithubActionRunner(); }); }; void loadSecretsAction(); diff --git a/docs/fork-pr-testing.md b/docs/fork-pr-testing.md new file mode 100644 index 0000000..c65162c --- /dev/null +++ b/docs/fork-pr-testing.md @@ -0,0 +1,32 @@ +# Fork PR Testing Guide + +This document explains how testing works for external pull requests from forks. + +## Overview + +The testing system consists of two main workflows: + +1. **E2E Tests** (`test-e2e.yml`) - Runs automatically for internal PRs, need manual trigger on external PRs. +2. **Ok To Test** (`ok-to-test.yml`) - Dispatches `repository_dispatch` event when maintainer puts the `/ok-to-test sha=` comment in the forked PR thread. + +## How It Works + +### 1. PR is created by maintainer: + +For the PR created by maintainer `E2E Test` workflow starts automatically. The PR check will reflect the status of the job. + +### 2. PR is created by external contributor: + +For the PR created by external contributor `E2E Test` workflow **won't** start automatically. +Maintainer should make a sanity check of the changes and run it manually by: + +1. Putting a comment `/ok-to-test sha=` in the PR thread. +2. `E2E Test` workflow starts. +3. After `E2E Test` workflow finishes, a comment with a link to the workflow, along with its status will be posted in the PR. +4. Maintainer can merge PR or request the changes based on the `E2E Test` results. + +## Notes + +- Only users with **write** permissions can trigger the `/ok-to-test` command. +- External PRs are automatically detected and prevented from running e2e tests automatically. +- Running e2e test on the external PR is optional. Maintainer can merge PR without running it. Maintainer decides whether it's needed to run an E2E test. diff --git a/docs/local-testing.md b/docs/local-testing.md new file mode 100644 index 0000000..21f76df --- /dev/null +++ b/docs/local-testing.md @@ -0,0 +1,46 @@ +# Local Testing Guide + +This document explains how to run e2e tests locally using `act`. + +## Prerequisites + +1. **Docker** installed and running +2. **act** installed ([install guide](https://github.com/nektos/act#installation)) + ```bash + brew install act # macOS + ``` +3. **1Password credentials** (see [Required Secrets](#required-secrets)) +4. Build action + +## Required env variables + +| Secret | Description | +| -------------------------- | --------------------- | +| `OP_SERVICE_ACCOUNT_TOKEN` | Service Account token | +| `VAULT` | Vault name or UUID | + +## Building Before Testing + +If you've modified TypeScript code, rebuild before running E2E tests: + +```bash +npm run build +``` + +## Testing + +### Run E2E tests using Service Account + +```bash +act push -W .github/workflows/e2e-tests.yml \ + -s OP_SERVICE_ACCOUNT_TOKEN="$OP_SERVICE_ACCOUNT_TOKEN" \ + -s VAULT="$VAULT" \ + -j test-service-account \ + --matrix os:ubuntu-latest +``` + +## Run unit tests + +```bash +npm test +``` diff --git a/package-lock.json b/package-lock.json index e53d88c..141e303 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "load-secrets-action", - "version": "3.1.0", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "load-secrets-action", - "version": "3.1.0", + "version": "3.0.0", "license": "MIT", "dependencies": { "@1password/op-js": "^0.1.11", "@actions/core": "^1.10.1", "@actions/exec": "^1.1.1", - "dotenv": "^17.2.2", - "op-cli-installer": "github:1Password/op-cli-installer#e6c1c758bc3339e5fe9b06255728039f688f73fa" + "@actions/tool-cache": "^2.0.2", + "dotenv": "^17.2.2" }, "devDependencies": { "@1password/eslint-config": "^4.3.1", @@ -172,6 +172,7 @@ "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.0", @@ -707,7 +708,6 @@ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -731,16 +731,14 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "Python-2.0", - "peer": true + "license": "Python-2.0" }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -754,7 +752,6 @@ "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -775,7 +772,6 @@ "deprecated": "Use @eslint/config-array instead", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -791,7 +787,6 @@ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=12.22" }, @@ -806,8 +801,7 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", "dev": true, - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -1462,6 +1456,7 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -1649,8 +1644,7 @@ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/@vercel/ncc": { "version": "0.38.3", @@ -1682,7 +1676,6 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1693,7 +1686,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2177,6 +2169,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -2671,8 +2664,7 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", @@ -2759,7 +2751,6 @@ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -3418,7 +3409,6 @@ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -3448,8 +3438,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, - "license": "Python-2.0", - "peer": true + "license": "Python-2.0" }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", @@ -3457,7 +3446,6 @@ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -3470,12 +3458,11 @@ } }, "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -3489,7 +3476,6 @@ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -3506,7 +3492,6 @@ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -3523,7 +3508,6 @@ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -3569,7 +3553,6 @@ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3659,8 +3642,7 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", @@ -3704,8 +3686,7 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fastq": { "version": "1.17.1", @@ -3733,7 +3714,6 @@ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -3807,7 +3787,6 @@ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -3822,8 +3801,7 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/for-each": { "version": "0.3.3", @@ -4024,7 +4002,6 @@ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -4038,7 +4015,6 @@ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -4264,7 +4240,6 @@ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -4631,7 +4606,6 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -4922,6 +4896,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -5539,9 +5514,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -5580,8 +5555,7 @@ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -5595,16 +5569,14 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", @@ -5641,7 +5613,6 @@ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "json-buffer": "3.0.1" } @@ -5692,7 +5663,6 @@ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -5949,8 +5919,7 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/log-update": { "version": "6.1.0", @@ -6399,35 +6368,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/op-cli-installer": { - "version": "1.0.0", - "resolved": "git+ssh://git@github.com/1Password/op-cli-installer.git#e6c1c758bc3339e5fe9b06255728039f688f73fa", - "integrity": "sha512-ueyYQAgtbIHP2QWx9iCiztoPov01GdxPZNZ4+Qg3IaAyC4khMIk4/vYPagRhRKta+HI6fWV6jO3/ajBj27KBZA==", - "license": "MIT", - "dependencies": { - "@actions/core": "^1.11.1", - "@actions/tool-cache": "^2.0.2", - "semver": "^7.7.2" - } - }, - "node_modules/op-cli-installer/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -6501,7 +6447,6 @@ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "callsites": "^3.0.0" }, @@ -6647,7 +6592,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8.0" } @@ -6736,7 +6680,6 @@ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -6885,7 +6828,6 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -6971,7 +6913,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -7594,8 +7535,7 @@ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tmpl": { "version": "1.0.5", @@ -7770,7 +7710,6 @@ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -7794,7 +7733,6 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=10" }, @@ -7886,6 +7824,7 @@ "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7969,7 +7908,6 @@ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -8108,7 +8046,6 @@ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 5895a64..6904483 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "load-secrets-action", - "version": "3.1.0", + "version": "3.0.0", "description": "Load Secrets from 1Password", "main": "dist/index.js", "directories": { @@ -43,8 +43,8 @@ "@1password/op-js": "^0.1.11", "@actions/core": "^1.10.1", "@actions/exec": "^1.1.1", - "dotenv": "^17.2.2", - "op-cli-installer": "github:1Password/op-cli-installer#e6c1c758bc3339e5fe9b06255728039f688f73fa" + "@actions/tool-cache": "^2.0.2", + "dotenv": "^17.2.2" }, "devDependencies": { "@1password/eslint-config": "^4.3.1", diff --git a/src/index.ts b/src/index.ts index 6469bcd..fcc2552 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ +import dotenv from "dotenv"; import * as core from "@actions/core"; import { validateCli } from "@1password/op-js"; -import { installCliOnGithubActionRunner } from "op-cli-installer"; -import dotenv from "dotenv"; +import { installCliOnGithubActionRunner } from "./op-cli-installer"; import { loadSecrets, unsetPrevious, validateAuth } from "./utils"; import { envFilePath } from "./constants"; diff --git a/src/op-cli-installer/github-action/cli-installer/cli-installer.ts b/src/op-cli-installer/github-action/cli-installer/cli-installer.ts new file mode 100644 index 0000000..820e179 --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/cli-installer.ts @@ -0,0 +1,58 @@ +import os from "os"; + +import * as core from "@actions/core"; +import * as tc from "@actions/tool-cache"; + +export type SupportedPlatform = Extract< + NodeJS.Platform, + "linux" | "darwin" | "win32" +>; + +// maps OS architecture names to 1Password CLI installer architecture names +export const archMap: Record = { + ia32: "386", + x64: "amd64", + arm: "arm", + arm64: "arm64", +}; + +// Builds the download URL for the 1Password CLI based on the platform and version. +export const cliUrlBuilder: Record< + SupportedPlatform, + (version: string, arch?: string) => string +> = { + linux: (version, arch) => + `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_linux_${arch}_${version}.zip`, + darwin: (version) => + `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_apple_universal_${version}.pkg`, + win32: (version, arch) => + `https://cache.agilebits.com/dist/1P/op2/pkg/${version}/op_windows_${arch}_${version}.zip`, +}; + +export class CliInstaller { + public readonly version: string; + public readonly arch: string; + + public constructor(version: string) { + this.version = version; + this.arch = this.getArch(); + } + + public async install(url: string): Promise { + console.info(`Downloading 1Password CLI from: ${url}`); + const downloadPath = await tc.downloadTool(url); + console.info("Installing 1Password CLI"); + const extractedPath = await tc.extractZip(downloadPath); + core.addPath(extractedPath); + core.info("1Password CLI installed"); + } + + private getArch(): string { + const arch = archMap[os.arch()]; + if (!arch) { + throw new Error("Unsupported architecture"); + } + + return arch; + } +} diff --git a/src/op-cli-installer/github-action/cli-installer/index.ts b/src/op-cli-installer/github-action/cli-installer/index.ts new file mode 100644 index 0000000..4b071e6 --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/index.ts @@ -0,0 +1 @@ +export { type Installer, newCliInstaller } from "./installer"; diff --git a/src/op-cli-installer/github-action/cli-installer/installer.test.ts b/src/op-cli-installer/github-action/cli-installer/installer.test.ts new file mode 100644 index 0000000..f94b8f2 --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/installer.test.ts @@ -0,0 +1,43 @@ +import os from "os"; + +import { newCliInstaller } from "./installer"; +import { LinuxInstaller } from "./linux"; +import { MacOsInstaller } from "./macos"; +import { WindowsInstaller } from "./windows"; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe("newCliInstaller", () => { + const version = "1.0.0"; + + afterEach(() => { + jest.resetAllMocks(); + }); + + it("should return LinuxInstaller for linux platform", () => { + jest.spyOn(os, "platform").mockReturnValue("linux"); + const installer = newCliInstaller(version); + expect(installer).toBeInstanceOf(LinuxInstaller); + }); + + it("should return MacOsInstaller for darwin platform", () => { + jest.spyOn(os, "platform").mockReturnValue("darwin"); + const installer = newCliInstaller(version); + expect(installer).toBeInstanceOf(MacOsInstaller); + }); + + it("should return WindowsInstaller for win32 platform", () => { + jest.spyOn(os, "platform").mockReturnValue("win32"); + const installer = newCliInstaller(version); + expect(installer).toBeInstanceOf(WindowsInstaller); + }); + + it("should throw error for unsupported platform", () => { + jest.spyOn(os, "platform").mockReturnValue("sunos"); + expect(() => newCliInstaller(version)).toThrow( + "Unsupported platform: sunos", + ); + }); +}); diff --git a/src/op-cli-installer/github-action/cli-installer/installer.ts b/src/op-cli-installer/github-action/cli-installer/installer.ts new file mode 100644 index 0000000..1e8f649 --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/installer.ts @@ -0,0 +1,23 @@ +import os from "os"; + +import { LinuxInstaller } from "./linux"; +import { MacOsInstaller } from "./macos"; +import { WindowsInstaller } from "./windows"; + +export interface Installer { + installCli(): Promise; +} + +export const newCliInstaller = (version: string): Installer => { + const platform = os.platform(); + switch (platform) { + case "linux": + return new LinuxInstaller(version); + case "darwin": + return new MacOsInstaller(version); + case "win32": + return new WindowsInstaller(version); + default: + throw new Error(`Unsupported platform: ${platform}`); + } +}; diff --git a/src/op-cli-installer/github-action/cli-installer/linux.test.ts b/src/op-cli-installer/github-action/cli-installer/linux.test.ts new file mode 100644 index 0000000..db8cd7a --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/linux.test.ts @@ -0,0 +1,38 @@ +import os from "os"; + +import { + archMap, + CliInstaller, + cliUrlBuilder, + type SupportedPlatform, +} from "./cli-installer"; +import { LinuxInstaller } from "./linux"; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe("LinuxInstaller", () => { + const version = "1.2.3"; + const arch: NodeJS.Architecture = "arm64"; + + it("should construct with given version and architecture", () => { + jest.spyOn(os, "arch").mockReturnValue(arch); + const installer = new LinuxInstaller(version); + expect(installer.version).toEqual(version); + expect(installer.arch).toEqual(archMap[arch]); + }); + + it("should call install with correct URL", async () => { + const installer = new LinuxInstaller(version); + const installMock = jest + .spyOn(CliInstaller.prototype, "install") + .mockResolvedValue(); + + await installer.installCli(); + + const builder = cliUrlBuilder["linux" as SupportedPlatform]; + const url = builder(version, installer.arch); + expect(installMock).toHaveBeenCalledWith(url); + }); +}); diff --git a/src/op-cli-installer/github-action/cli-installer/linux.ts b/src/op-cli-installer/github-action/cli-installer/linux.ts new file mode 100644 index 0000000..8d7c8ed --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/linux.ts @@ -0,0 +1,19 @@ +import { + CliInstaller, + cliUrlBuilder, + type SupportedPlatform, +} from "./cli-installer"; +import type { Installer } from "./installer"; + +export class LinuxInstaller extends CliInstaller implements Installer { + private readonly platform: SupportedPlatform = "linux"; // Node.js platform identifier for Linux + + public constructor(version: string) { + super(version); + } + + public async installCli(): Promise { + const urlBuilder = cliUrlBuilder[this.platform]; + await super.install(urlBuilder(this.version, this.arch)); + } +} diff --git a/src/op-cli-installer/github-action/cli-installer/macos.test.ts b/src/op-cli-installer/github-action/cli-installer/macos.test.ts new file mode 100644 index 0000000..ebbc64f --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/macos.test.ts @@ -0,0 +1,35 @@ +import os from "os"; + +import { + archMap, + cliUrlBuilder, + type SupportedPlatform, +} from "./cli-installer"; +import { MacOsInstaller } from "./macos"; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe("MacOsInstaller", () => { + const version = "1.2.3"; + const arch: NodeJS.Architecture = "x64"; + + it("should construct with given version and architecture", () => { + jest.spyOn(os, "arch").mockReturnValue(arch); + const installer = new MacOsInstaller(version); + expect(installer.version).toEqual(version); + expect(installer.arch).toEqual(archMap[arch]); + }); + + it("should call install with correct URL", async () => { + const installer = new MacOsInstaller(version); + const installMock = jest.spyOn(installer, "install").mockResolvedValue(); + + await installer.installCli(); + + const builder = cliUrlBuilder["darwin" as SupportedPlatform]; + const url = builder(version, installer.arch); + expect(installMock).toHaveBeenCalledWith(url); + }); +}); diff --git a/src/op-cli-installer/github-action/cli-installer/macos.ts b/src/op-cli-installer/github-action/cli-installer/macos.ts new file mode 100644 index 0000000..f5cd7e5 --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/macos.ts @@ -0,0 +1,49 @@ +import { execFile } from "child_process"; +import * as fs from "fs"; +import * as path from "path"; +import { promisify } from "util"; + +import * as core from "@actions/core"; +import * as tc from "@actions/tool-cache"; + +import { + CliInstaller, + cliUrlBuilder, + type SupportedPlatform, +} from "./cli-installer"; +import { type Installer } from "./installer"; + +const execFileAsync = promisify(execFile); + +export class MacOsInstaller extends CliInstaller implements Installer { + private readonly platform: SupportedPlatform = "darwin"; // Node.js platform identifier for macOS + + public constructor(version: string) { + super(version); + } + + public async installCli(): Promise { + const urlBuilder = cliUrlBuilder[this.platform]; + await this.install(urlBuilder(this.version)); + } + + // @actions/tool-cache package does not support .pkg files, so we need to handle the installation manually + public override async install(downloadUrl: string): Promise { + console.info(`Downloading 1Password CLI from: ${downloadUrl}`); + const pkgPath = await tc.downloadTool(downloadUrl); + const pkgWithExtension = `${pkgPath}.pkg`; + fs.renameSync(pkgPath, pkgWithExtension); + + const expandDir = "temp-pkg"; + await execFileAsync("pkgutil", ["--expand", pkgWithExtension, expandDir]); + const payloadPath = path.join(expandDir, "op.pkg", "Payload"); + console.info("Installing 1Password CLI"); + const cliPath = await tc.extractTar(payloadPath); + core.addPath(cliPath); + + fs.rmSync(expandDir, { recursive: true, force: true }); + fs.rmSync(pkgPath, { force: true }); + + core.info("1Password CLI installed"); + } +} diff --git a/src/op-cli-installer/github-action/cli-installer/windows.test.ts b/src/op-cli-installer/github-action/cli-installer/windows.test.ts new file mode 100644 index 0000000..7b91d3d --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/windows.test.ts @@ -0,0 +1,38 @@ +import os from "os"; + +import { + archMap, + CliInstaller, + cliUrlBuilder, + type SupportedPlatform, +} from "./cli-installer"; +import { WindowsInstaller } from "./windows"; + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe("WindowsInstaller", () => { + const version = "1.2.3"; + const arch: NodeJS.Architecture = "x64"; + + it("should construct with given version and architecture", () => { + jest.spyOn(os, "arch").mockReturnValue(arch); + const installer = new WindowsInstaller(version); + expect(installer.version).toEqual(version); + expect(installer.arch).toEqual(archMap[arch]); + }); + + it("should call install with correct URL", async () => { + const installer = new WindowsInstaller(version); + const installMock = jest + .spyOn(CliInstaller.prototype, "install") + .mockResolvedValue(); + + await installer.installCli(); + + const builder = cliUrlBuilder["win32" as SupportedPlatform]; + const url = builder(version, installer.arch); + expect(installMock).toHaveBeenCalledWith(url); + }); +}); diff --git a/src/op-cli-installer/github-action/cli-installer/windows.ts b/src/op-cli-installer/github-action/cli-installer/windows.ts new file mode 100644 index 0000000..b1d37cb --- /dev/null +++ b/src/op-cli-installer/github-action/cli-installer/windows.ts @@ -0,0 +1,19 @@ +import { + CliInstaller, + cliUrlBuilder, + type SupportedPlatform, +} from "./cli-installer"; +import type { Installer } from "./installer"; + +export class WindowsInstaller extends CliInstaller implements Installer { + private readonly platform: SupportedPlatform = "win32"; // Node.js platform identifier for Windows + + public constructor(version: string) { + super(version); + } + + public async installCli(): Promise { + const urlBuilder = cliUrlBuilder[this.platform]; + await super.install(urlBuilder(this.version, this.arch)); + } +} diff --git a/src/op-cli-installer/github-action/index.ts b/src/op-cli-installer/github-action/index.ts new file mode 100644 index 0000000..85f242f --- /dev/null +++ b/src/op-cli-installer/github-action/index.ts @@ -0,0 +1,18 @@ +import * as core from "@actions/core"; + +import { ReleaseChannel, VersionResolver } from "../version"; + +import { newCliInstaller } from "./cli-installer"; + +// Installs the 1Password CLI on a GitHub Action runner. +export const installCliOnGithubActionRunner = async ( + version?: string, +): Promise => { + // Get the version from parameter, if not passed - from the job input. Defaults to latest if no version is provided + const providedVersion = + version || core.getInput("version") || ReleaseChannel.latest; + const versionResolver = new VersionResolver(providedVersion); + await versionResolver.resolve(); + const installer = newCliInstaller(versionResolver.get()); + await installer.installCli(); +}; diff --git a/src/op-cli-installer/index.test.ts b/src/op-cli-installer/index.test.ts new file mode 100644 index 0000000..b2120d7 --- /dev/null +++ b/src/op-cli-installer/index.test.ts @@ -0,0 +1,81 @@ +import * as core from "@actions/core"; + +import { newCliInstaller } from "./github-action/cli-installer"; +import { + installCliOnGithubActionRunner, + ReleaseChannel, + VersionResolver, +} from "./index"; + +jest.mock("./github-action/cli-installer", () => ({ + newCliInstaller: jest.fn().mockImplementation((_resolved: string) => ({ + installCli: jest.fn(), + })), +})); + +beforeEach(() => { + jest.restoreAllMocks(); +}); + +describe("installCliOnGithubActionRunner", () => { + it("should defaults to `latest` when nothing is passed", async () => { + jest.spyOn(core, "getInput").mockReturnValue(""); + jest.spyOn(VersionResolver.prototype, "resolve").mockResolvedValue(); + jest + .spyOn(VersionResolver.prototype, "get") + .mockReturnValue(ReleaseChannel.latest); + + await installCliOnGithubActionRunner(); + + expect(newCliInstaller).toHaveBeenCalledWith(ReleaseChannel.latest); + }); + + it("should defaults to `latest` when undefined is passed", async () => { + jest.spyOn(core, "getInput").mockReturnValue(""); + jest.spyOn(VersionResolver.prototype, "resolve").mockResolvedValue(); + jest + .spyOn(VersionResolver.prototype, "get") + .mockReturnValue(ReleaseChannel.latest); + + await installCliOnGithubActionRunner(undefined); + + expect(newCliInstaller).toHaveBeenCalledWith(ReleaseChannel.latest); + }); + + it("should set provided explicit version", async () => { + const providedVersion = "1.2.3"; + jest.spyOn(core, "getInput").mockReturnValue(""); + jest.spyOn(VersionResolver.prototype, "resolve").mockResolvedValue(); + jest + .spyOn(VersionResolver.prototype, "get") + .mockReturnValue(providedVersion); + + await installCliOnGithubActionRunner(providedVersion); + + expect(newCliInstaller).toHaveBeenCalledWith(providedVersion); + }); + + it("should set version provided as job input", async () => { + const providedVersion = "3.0.0"; + jest.spyOn(core, "getInput").mockReturnValue(providedVersion); + jest.spyOn(VersionResolver.prototype, "resolve").mockResolvedValue(); + jest + .spyOn(VersionResolver.prototype, "get") + .mockReturnValue(providedVersion); + + await installCliOnGithubActionRunner(); + + expect(newCliInstaller).toHaveBeenCalledWith(providedVersion); + }); + + it("should throw error for invalid version", async () => { + const providedVersion = "invalid"; + jest.spyOn(core, "getInput").mockReturnValue(providedVersion); + jest.spyOn(VersionResolver.prototype, "resolve").mockResolvedValue(); + jest + .spyOn(VersionResolver.prototype, "get") + .mockReturnValue(providedVersion); + + await expect(installCliOnGithubActionRunner()).rejects.toThrow(); + }); +}); diff --git a/src/op-cli-installer/index.ts b/src/op-cli-installer/index.ts new file mode 100644 index 0000000..852f623 --- /dev/null +++ b/src/op-cli-installer/index.ts @@ -0,0 +1,2 @@ +export { installCliOnGithubActionRunner } from "./github-action"; +export { ReleaseChannel, VersionResolver } from "./version"; diff --git a/src/op-cli-installer/version/constants.ts b/src/op-cli-installer/version/constants.ts new file mode 100644 index 0000000..cf59f5d --- /dev/null +++ b/src/op-cli-installer/version/constants.ts @@ -0,0 +1,13 @@ +export enum ReleaseChannel { + latest = "latest", + latestBeta = "latest-beta", +} + +export interface VersionResponse { + // eslint disabled next line as CLI2 is expected in getting CLI versions response + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + CLI2: { + release: { version: string }; + beta: { version: string }; + }; +} diff --git a/src/op-cli-installer/version/helper.test.ts b/src/op-cli-installer/version/helper.test.ts new file mode 100644 index 0000000..c6f0185 --- /dev/null +++ b/src/op-cli-installer/version/helper.test.ts @@ -0,0 +1,91 @@ +import { ReleaseChannel } from "./constants"; +import { getLatestVersion } from "./helper"; + +describe("getLatestVersion", () => { + beforeEach(() => { + jest.restoreAllMocks(); + }); + + it("should return latest stable version", async () => { + const mockResponse = { + // eslint-disable-next-line @typescript-eslint/naming-convention + CLI2: { + release: { version: "2.31.0" }, + beta: { version: "2.32.0-beta.01" }, + }, + }; + + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + // eslint-disable-next-line @typescript-eslint/require-await + json: async () => mockResponse, + } as Response); + + const version = await getLatestVersion(ReleaseChannel.latest); + expect(version).toBe("2.31.0"); + }); + + it("should return latest beta version", async () => { + const mockResponse = { + // eslint-disable-next-line @typescript-eslint/naming-convention + CLI2: { + release: { version: "2.31.0" }, + beta: { version: "2.32.0-beta.01" }, + }, + }; + + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + // eslint-disable-next-line @typescript-eslint/require-await + json: async () => mockResponse, + } as Response); + + const version = await getLatestVersion(ReleaseChannel.latestBeta); + expect(version).toBe("2.32.0-beta.01"); + }); + + it("should throw if no CLI2 field", async () => { + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + // eslint-disable-next-line @typescript-eslint/require-await + json: async () => ({}), + } as Response); + + await expect(getLatestVersion(ReleaseChannel.latest)).rejects.toThrow( + `No ${ReleaseChannel.latest} versions found`, + ); + }); + + it("should throw if no stable version found", async () => { + const mockResponse = { + // eslint-disable-next-line @typescript-eslint/naming-convention + CLI2: { + beta: { version: "2.32.0-beta.01" }, + }, + }; + + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + // eslint-disable-next-line @typescript-eslint/require-await + json: async () => mockResponse, + } as Response); + + await expect(getLatestVersion(ReleaseChannel.latest)).rejects.toThrow( + `No ${ReleaseChannel.latest} versions found`, + ); + }); + + it("should throw if no beta version found", async () => { + const mockResponse = { + // eslint-disable-next-line @typescript-eslint/naming-convention + CLI2: { + release: { version: "2.32.0" }, + }, + }; + + jest.spyOn(global, "fetch").mockResolvedValueOnce({ + // eslint-disable-next-line @typescript-eslint/require-await + json: async () => mockResponse, + } as Response); + + await expect(getLatestVersion(ReleaseChannel.latestBeta)).rejects.toThrow( + `No ${ReleaseChannel.latestBeta} versions found`, + ); + }); +}); diff --git a/src/op-cli-installer/version/helper.ts b/src/op-cli-installer/version/helper.ts new file mode 100644 index 0000000..1d246dc --- /dev/null +++ b/src/op-cli-installer/version/helper.ts @@ -0,0 +1,23 @@ +import * as core from "@actions/core"; + +import { ReleaseChannel, type VersionResponse } from "./constants"; + +// Returns the latest version of the 1Password CLI based on the specified channel. +export const getLatestVersion = async ( + channel: ReleaseChannel, +): Promise => { + core.info(`Getting ${channel} version number`); + const res = await fetch("https://app-updates.agilebits.com/latest"); + const json = (await res.json()) as VersionResponse; + const latestStable = json?.CLI2?.release?.version; + const latestBeta = json?.CLI2?.beta?.version; + const version = + channel === ReleaseChannel.latestBeta ? latestBeta : latestStable; + + if (!version) { + core.error(`No ${channel} versions found`); + throw new Error(`No ${channel} versions found`); + } + + return version; +}; diff --git a/src/op-cli-installer/version/index.ts b/src/op-cli-installer/version/index.ts new file mode 100644 index 0000000..387cf2a --- /dev/null +++ b/src/op-cli-installer/version/index.ts @@ -0,0 +1,2 @@ +export { VersionResolver } from "./version-resolver"; +export { ReleaseChannel } from "./constants"; diff --git a/src/op-cli-installer/version/validate.test.ts b/src/op-cli-installer/version/validate.test.ts new file mode 100644 index 0000000..ff4a201 --- /dev/null +++ b/src/op-cli-installer/version/validate.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it } from "@jest/globals"; + +import { validateVersion } from "./validate"; + +describe("validateVersion", () => { + it('should not throw for "latest"', () => { + expect(() => validateVersion("latest")).not.toThrow(); + }); + + it('should not throw for "latest-beta"', () => { + expect(() => validateVersion("latest-beta")).not.toThrow(); + }); + + it('should not throw for valid semver version "2.18.0"', () => { + expect(() => validateVersion("2.18.0")).not.toThrow(); + }); + + it('should throw for partial version "2"', () => { + expect(() => validateVersion("2")).toThrow(); + }); + + it('should throw for partial version "2.1"', () => { + expect(() => validateVersion("2.1")).toThrow(); + }); + + it('should not throw for valid beta "2.19.0-beta.01"', () => { + expect(() => validateVersion("2.19.0-beta.01")).not.toThrow(); + }); + + it('should not throw for valid beta "2.19.3-beta.12"', () => { + expect(() => validateVersion("2.19.3-beta.12")).not.toThrow(); + }); + + it('should not throw for coerced version "v2.19.0"', () => { + expect(() => validateVersion("v2.19.0")).not.toThrow(); + }); + + it('should throw for invalid version "latest-abc"', () => { + expect(() => validateVersion("latest-abc")).toThrow(); + }); + + it("should throw for empty string", () => { + expect(() => validateVersion("")).toThrow(); + }); +}); diff --git a/src/op-cli-installer/version/validate.ts b/src/op-cli-installer/version/validate.ts new file mode 100644 index 0000000..39967dd --- /dev/null +++ b/src/op-cli-installer/version/validate.ts @@ -0,0 +1,23 @@ +import semver from "semver"; + +import { ReleaseChannel } from "./constants"; + +// Validates if the provided version type is a valid enum value or a valid semver version. +export const validateVersion = (input: string): void => { + if (Object.values(ReleaseChannel).includes(input as ReleaseChannel)) { + return; + } + + // 1Password beta releases (aka 2.19.0-beta.01) are not semver compliant. + // According to semver, it should be "2.19.0-beta.1". + // That's why we need to normalize them before validating. + // Accepts valid semver versions like "2.18.0" or beta-releases like "2.19.0-beta.01" + // or versions with 'v' prefix like "v2.19.0" + const normalized = input.replace(/-beta\.0*(\d+)/, "-beta.$1"); + const normInput = new semver.SemVer(normalized); + if (semver.valid(normInput)) { + return; + } + + throw new Error(`Invalid version input: ${input}`); +}; diff --git a/src/op-cli-installer/version/version-resolver.test.ts b/src/op-cli-installer/version/version-resolver.test.ts new file mode 100644 index 0000000..5166607 --- /dev/null +++ b/src/op-cli-installer/version/version-resolver.test.ts @@ -0,0 +1,58 @@ +import { expect } from "@jest/globals"; + +import { ReleaseChannel } from "./constants"; +import { VersionResolver } from "./version-resolver"; + +describe("VersionResolver", () => { + test("should throw error when invalid version provided", () => { + expect(() => new VersionResolver("vv")).toThrow(); + }); + + test("should throw error when version is empty", () => { + expect(() => new VersionResolver("")).toThrow(); + }); + + test("should throw error for major version only", () => { + expect(() => new VersionResolver("1")).toThrow(); + }); + + test("should throw error for major and minor version only", () => { + expect(() => new VersionResolver("1.0")).toThrow(); + }); + + test("should resolve latest stable version", async () => { + const versionResolver = new VersionResolver(ReleaseChannel.latest); + await versionResolver.resolve(); + expect(versionResolver.get()).toBeDefined(); + }); + + test("should resolve latest beta version", async () => { + const versionResolver = new VersionResolver(ReleaseChannel.latestBeta); + await versionResolver.resolve(); + expect(versionResolver.get()).toBeDefined(); + }); + + test("should resolve version without 'v' prefix", async () => { + const versionResolver = new VersionResolver("1.0.0"); + await versionResolver.resolve(); + expect(versionResolver.get()).toBe("v1.0.0"); + }); + + test("should resolve version with 'v' prefix", async () => { + const versionResolver = new VersionResolver("v1.0.0"); + await versionResolver.resolve(); + expect(versionResolver.get()).toBe("v1.0.0"); + }); + + test("should resolve beta version without 'v' prefix", async () => { + const versionResolver = new VersionResolver("2.19.0-beta.01"); + await versionResolver.resolve(); + expect(versionResolver.get()).toBe("v2.19.0-beta.01"); + }); + + test("should resolve beta version with 'v' prefix", async () => { + const versionResolver = new VersionResolver("v2.19.0-beta.01"); + await versionResolver.resolve(); + expect(versionResolver.get()).toBe("v2.19.0-beta.01"); + }); +}); diff --git a/src/op-cli-installer/version/version-resolver.ts b/src/op-cli-installer/version/version-resolver.ts new file mode 100644 index 0000000..d74ba4f --- /dev/null +++ b/src/op-cli-installer/version/version-resolver.ts @@ -0,0 +1,45 @@ +import * as core from "@actions/core"; + +import { ReleaseChannel } from "./constants"; +import { getLatestVersion } from "./helper"; +import { validateVersion } from "./validate"; + +export class VersionResolver { + private version: string; + + public constructor(version: string) { + this.validate(version); + this.version = version; + } + + public get(): string { + return this.version; + } + + public async resolve(): Promise { + core.info(`Resolving version: ${this.version}`); + if (!this.version) { + core.error("Version is not provided"); + throw new Error("Version is not provided"); + } + + if (this.isReleaseChannel(this.version)) { + this.version = await getLatestVersion(this.version); + } + + // add `v` prefix if not already present + this.version = this.version.startsWith("v") + ? this.version + : `v${this.version}`; + } + + private validate(version: string) { + core.info(`Validating version number: '${version}'`); + validateVersion(version); + core.info(`Version number '${version}' is valid`); + } + + private isReleaseChannel(value: string): value is ReleaseChannel { + return Object.values(ReleaseChannel).includes(value as ReleaseChannel); + } +}