mirror of
https://github.com/thegeeklab/wp-git-clone.git
synced 2024-11-21 04:00:40 +00:00
initial commit
This commit is contained in:
commit
378831f327
4
.dictionary
Normal file
4
.dictionary
Normal file
@ -0,0 +1,4 @@
|
||||
userid
|
||||
url
|
||||
roomid
|
||||
wp-git-clone
|
71
.github/settings.yml
vendored
Normal file
71
.github/settings.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
repository:
|
||||
name: wp-git-clone
|
||||
description: Woodpecker CI plugin to clone git repositories
|
||||
homepage: https://woodpecker-plugins.geekdocs.de/plugins/wp-git-clone
|
||||
topics: woodpecker-ci, woodpecker, woodpecker-plugin
|
||||
|
||||
private: false
|
||||
has_issues: true
|
||||
has_wiki: false
|
||||
has_downloads: true
|
||||
|
||||
default_branch: main
|
||||
|
||||
allow_squash_merge: true
|
||||
allow_merge_commit: true
|
||||
allow_rebase_merge: true
|
||||
|
||||
labels:
|
||||
- name: bug
|
||||
color: d73a4a
|
||||
description: Something isn't working
|
||||
- name: documentation
|
||||
color: 0075ca
|
||||
description: Improvements or additions to documentation
|
||||
- name: duplicate
|
||||
color: cfd3d7
|
||||
description: This issue or pull request already exists
|
||||
- name: enhancement
|
||||
color: a2eeef
|
||||
description: New feature or request
|
||||
- name: good first issue
|
||||
color: 7057ff
|
||||
description: Good for newcomers
|
||||
- name: help wanted
|
||||
color: 008672
|
||||
description: Extra attention is needed
|
||||
- name: invalid
|
||||
color: e4e669
|
||||
description: This doesn't seem right
|
||||
- name: question
|
||||
color: d876e3
|
||||
description: Further information is requested
|
||||
- name: wontfix
|
||||
color: ffffff
|
||||
description: This will not be worked on
|
||||
|
||||
branches:
|
||||
- name: main
|
||||
protection:
|
||||
required_pull_request_reviews: null
|
||||
required_status_checks:
|
||||
strict: false
|
||||
contexts:
|
||||
- ci/woodpecker/pr/test
|
||||
- ci/woodpecker/pr/build-package
|
||||
- ci/woodpecker/pr/build-container
|
||||
- ci/woodpecker/pr/docs
|
||||
enforce_admins: false
|
||||
required_linear_history: true
|
||||
restrictions: null
|
||||
- name: docs
|
||||
protection:
|
||||
required_pull_request_reviews: null
|
||||
required_status_checks: null
|
||||
enforce_admins: true
|
||||
required_linear_history: true
|
||||
restrictions:
|
||||
apps: []
|
||||
users: []
|
||||
teams:
|
||||
- bot
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/dist
|
||||
/release
|
||||
/wp-git-clone*
|
||||
docs/data/data-raw.yaml
|
||||
|
||||
coverage.out
|
||||
CHANGELOG.md
|
47
.gitsv/config.yml
Normal file
47
.gitsv/config.yml
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
version: "1.1"
|
||||
|
||||
versioning:
|
||||
update-major: []
|
||||
update-minor: [feat]
|
||||
update-patch: [fix, perf, refactor, chore, test, ci, docs]
|
||||
|
||||
tag:
|
||||
pattern: "v%d.%d.%d"
|
||||
|
||||
release-notes:
|
||||
sections:
|
||||
- name: Features
|
||||
commit-types: [feat]
|
||||
section-type: commits
|
||||
- name: Bug Fixes
|
||||
commit-types: [fix]
|
||||
section-type: commits
|
||||
- name: Performance Improvements
|
||||
commit-types: [perf]
|
||||
section-type: commits
|
||||
- name: Code Refactoring
|
||||
commit-types: [refactor]
|
||||
section-type: commits
|
||||
- name: Others
|
||||
commit-types: [chore]
|
||||
section-type: commits
|
||||
- name: Testing
|
||||
commit-types: [test]
|
||||
section-type: commits
|
||||
- name: CI Pipeline
|
||||
commit-types: [ci]
|
||||
section-type: commits
|
||||
- name: Documentation
|
||||
commit-types: [docs]
|
||||
section-type: commits
|
||||
- name: BREAKING CHANGES
|
||||
section-type: breaking-changes
|
||||
|
||||
commit-message:
|
||||
footer:
|
||||
issue:
|
||||
key: issue
|
||||
add-value-prefix: "#"
|
||||
issue:
|
||||
regex: "#?[0-9]+"
|
104
.golangci.yml
Normal file
104
.golangci.yml
Normal file
@ -0,0 +1,104 @@
|
||||
linters:
|
||||
enable-all: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
- asasalint
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- containedctx
|
||||
- contextcheck
|
||||
- decorder
|
||||
- dogsled
|
||||
- dupl
|
||||
- dupword
|
||||
- durationcheck
|
||||
- errchkjson
|
||||
- errname
|
||||
- errorlint
|
||||
- execinquery
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- forcetypeassert
|
||||
- ginkgolinter
|
||||
- gocheckcompilerdirectives
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godot
|
||||
- godox
|
||||
- goerr113
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goheader
|
||||
- goimports
|
||||
- gomnd
|
||||
- gomoddirectives
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- grouper
|
||||
- importas
|
||||
- interfacebloat
|
||||
- ireturn
|
||||
- lll
|
||||
- loggercheck
|
||||
- maintidx
|
||||
- makezero
|
||||
- misspell
|
||||
- musttag
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilerr
|
||||
- nilnil
|
||||
- nlreturn
|
||||
- noctx
|
||||
- nolintlint
|
||||
- nonamedreturns
|
||||
- nosprintfhostport
|
||||
- prealloc
|
||||
- predeclared
|
||||
- promlinter
|
||||
- reassign
|
||||
- revive
|
||||
# - rowserrcheck
|
||||
# - sqlclosecheck
|
||||
# - structcheck
|
||||
- stylecheck
|
||||
- tagliatelle
|
||||
- tenv
|
||||
- testableexamples
|
||||
- thelper
|
||||
- tparallel
|
||||
- unconvert
|
||||
- unparam
|
||||
- usestdlibvars
|
||||
# - wastedassign
|
||||
- whitespace
|
||||
- wsl
|
||||
- zerologlint
|
||||
fast: false
|
||||
|
||||
run:
|
||||
timeout: 3m
|
||||
|
||||
linters-settings:
|
||||
gofumpt:
|
||||
extra-rules: true
|
||||
ireturn:
|
||||
allow:
|
||||
- anon
|
||||
- error
|
||||
- empty
|
||||
- stdlib
|
||||
- ^github\.com\/cenkalti\/backoff\/\S+\.BackOff$
|
1
.lycheeignore
Normal file
1
.lycheeignore
Normal file
@ -0,0 +1 @@
|
||||
https://hub.docker.com/r/thegeeklab/*
|
6
.markdownlint.yml
Normal file
6
.markdownlint.yml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
default: True
|
||||
MD013: False
|
||||
MD041: False
|
||||
MD004:
|
||||
style: dash
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
||||
*.tpl.md
|
||||
LICENSE
|
66
.woodpecker/build-container.yml
Normal file
66
.woodpecker/build-container.yml
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: dryrun
|
||||
image: quay.io/thegeeklab/wp-docker-buildx:2
|
||||
settings:
|
||||
containerfile: Containerfile.multiarch
|
||||
dry_run: true
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
provenance: false
|
||||
repo: ${CI_REPO}
|
||||
when:
|
||||
- event: [pull_request]
|
||||
|
||||
publish-dockerhub:
|
||||
group: container
|
||||
image: quay.io/thegeeklab/wp-docker-buildx:2
|
||||
settings:
|
||||
auto_tag: true
|
||||
containerfile: Containerfile.multiarch
|
||||
password:
|
||||
from_secret: docker_password
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
provenance: false
|
||||
repo: ${CI_REPO}
|
||||
username:
|
||||
from_secret: docker_username
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
publish-quay:
|
||||
group: container
|
||||
image: quay.io/thegeeklab/wp-docker-buildx:2
|
||||
settings:
|
||||
auto_tag: true
|
||||
containerfile: Containerfile.multiarch
|
||||
password:
|
||||
from_secret: quay_password
|
||||
platforms:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
provenance: false
|
||||
registry: quay.io
|
||||
repo: quay.io/${CI_REPO}
|
||||
username:
|
||||
from_secret: quay_username
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
depends_on:
|
||||
- test
|
41
.woodpecker/build-package.yml
Normal file
41
.woodpecker/build-package.yml
Normal file
@ -0,0 +1,41 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: docker.io/techknowlogick/xgo:go-1.21.x
|
||||
commands:
|
||||
- ln -s $(pwd) /source
|
||||
- make release
|
||||
|
||||
- name: executable
|
||||
image: quay.io/thegeeklab/alpine-tools
|
||||
commands:
|
||||
- $(find dist/ -executable -type f -iname ${CI_REPO_NAME}-linux-amd64) --help
|
||||
|
||||
- name: changelog
|
||||
image: quay.io/thegeeklab/git-sv
|
||||
commands:
|
||||
- git sv current-version
|
||||
- git sv release-notes -t ${CI_COMMIT_TAG:-next} -o CHANGELOG.md
|
||||
- cat CHANGELOG.md
|
||||
|
||||
- name: publish-github
|
||||
image: docker.io/plugins/github-release
|
||||
settings:
|
||||
api_key:
|
||||
from_secret: github_token
|
||||
files:
|
||||
- dist/*
|
||||
note: CHANGELOG.md
|
||||
overwrite: true
|
||||
title: ${CI_COMMIT_TAG}
|
||||
when:
|
||||
- event: [tag]
|
||||
|
||||
depends_on:
|
||||
- test
|
79
.woodpecker/docs.yml
Normal file
79
.woodpecker/docs.yml
Normal file
@ -0,0 +1,79 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: markdownlint
|
||||
image: quay.io/thegeeklab/markdownlint-cli
|
||||
group: test
|
||||
commands:
|
||||
- markdownlint 'README.md' 'CONTRIBUTING.md'
|
||||
|
||||
- name: spellcheck
|
||||
image: quay.io/thegeeklab/alpine-tools
|
||||
group: test
|
||||
commands:
|
||||
- spellchecker --files '_docs/**/*.md' 'README.md' 'CONTRIBUTING.md' -d .dictionary -p spell indefinite-article syntax-urls
|
||||
environment:
|
||||
FORCE_COLOR: "true"
|
||||
|
||||
- name: link-validation
|
||||
image: docker.io/lycheeverse/lychee
|
||||
group: test
|
||||
commands:
|
||||
- lychee --no-progress --format detailed _docs/content README.md
|
||||
|
||||
- name: publish
|
||||
image: quay.io/thegeeklab/wp-git-action
|
||||
settings:
|
||||
action:
|
||||
- pages
|
||||
author_email: bot@thegeeklab.de
|
||||
author_name: thegeeklab-bot
|
||||
branch: docs
|
||||
message: "[skip ci] auto-update documentation"
|
||||
netrc_password:
|
||||
from_secret: github_token
|
||||
pages_directory: _docs/
|
||||
when:
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
- name: pushrm-dockerhub
|
||||
image: docker.io/chko/docker-pushrm:1
|
||||
secrets:
|
||||
- source: docker_password
|
||||
target: DOCKER_PASS
|
||||
- source: docker_username
|
||||
target: DOCKER_USER
|
||||
environment:
|
||||
PUSHRM_FILE: README.md
|
||||
PUSHRM_SHORT: Woodpecker CI plugin to clone git repositories
|
||||
PUSHRM_TARGET: ${CI_REPO}
|
||||
when:
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
status: [success]
|
||||
|
||||
- name: pushrm-quay
|
||||
image: docker.io/chko/docker-pushrm:1
|
||||
secrets:
|
||||
- source: quay_token
|
||||
target: APIKEY__QUAY_IO
|
||||
environment:
|
||||
PUSHRM_FILE: README.md
|
||||
PUSHRM_TARGET: quay.io/${CI_REPO}
|
||||
when:
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
status: [success]
|
||||
|
||||
depends_on:
|
||||
- build-package
|
||||
- build-container
|
26
.woodpecker/notify.yml
Normal file
26
.woodpecker/notify.yml
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
when:
|
||||
- event: [tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
runs_on: [success, failure]
|
||||
|
||||
steps:
|
||||
- name: matrix
|
||||
image: quay.io/thegeeklab/wp-matrix
|
||||
settings:
|
||||
homeserver:
|
||||
from_secret: matrix_homeserver
|
||||
password:
|
||||
from_secret: matrix_password
|
||||
roomid:
|
||||
from_secret: matrix_roomid
|
||||
username:
|
||||
from_secret: matrix_username
|
||||
when:
|
||||
- status: [success, failure]
|
||||
|
||||
depends_on:
|
||||
- docs
|
17
.woodpecker/test.yml
Normal file
17
.woodpecker/test.yml
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
when:
|
||||
- event: [pull_request, tag]
|
||||
- event: [push, manual]
|
||||
branch:
|
||||
- ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
- name: lint
|
||||
image: docker.io/library/golang:1.21
|
||||
commands:
|
||||
- make lint
|
||||
|
||||
- name: test
|
||||
image: docker.io/library/golang:1.21
|
||||
commands:
|
||||
- make test
|
31
CONTRIBUTING.md
Normal file
31
CONTRIBUTING.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
## Security
|
||||
|
||||
If you think you have found a **security issue**, please do not mention it in this repository.
|
||||
Instead, send an email to `security@thegeeklab.de` with as many details as possible so it can be handled confidential.
|
||||
|
||||
## Bug Reports and Feature Requests
|
||||
|
||||
If you have found a **bug** or have a **feature request** please use the search first in case a similar issue already exists.
|
||||
If not, please create an issue in this repository
|
||||
|
||||
## Code
|
||||
|
||||
If you would like to fix a bug or implement a feature, please fork the repository and create a Pull Request.
|
||||
|
||||
Before you start any Pull Request, it is recommended that you create an issue to discuss first if you have any
|
||||
doubts about requirement or implementation. That way you can be sure that the maintainer(s) agree on what to change and how,
|
||||
and you can hopefully get a quick merge afterwards.
|
||||
|
||||
Pull Requests can only be merged once all status checks are green.
|
||||
|
||||
## Do not force push to your Pull Request branch
|
||||
|
||||
Please do not force push to your Pull Requests branch after you have created your Pull Request, as doing so makes it harder for us to review your work.
|
||||
Pull Requests will always be squashed by us when we merge your work. Commit as many times as you need in your Pull Request branch.
|
||||
|
||||
## Re-requesting a review
|
||||
|
||||
Please do not ping your reviewer(s) by mentioning them in a new comment. Instead, use the re-request review functionality.
|
||||
Read more about this in the [GitHub docs, Re-requesting a review](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request#re-requesting-a-review).
|
25
Containerfile.multiarch
Normal file
25
Containerfile.multiarch
Normal file
@ -0,0 +1,25 @@
|
||||
FROM --platform=$BUILDPLATFORM golang:1.21@sha256:672a2286da3ee7a854c3e0a56e0838918d0dbb1c18652992930293312de898a6 as build
|
||||
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
|
||||
ADD . /src
|
||||
WORKDIR /src
|
||||
|
||||
RUN make build
|
||||
|
||||
FROM alpine:3.19@sha256:51b67269f354137895d43f3b3d810bfacd3945438e94dc5ac55fdac340352f48
|
||||
|
||||
LABEL maintainer="Robert Kaussow <mail@thegeeklab.de>"
|
||||
LABEL org.opencontainers.image.authors="Robert Kaussow <mail@thegeeklab.de>"
|
||||
LABEL org.opencontainers.image.title="wp-git-clone"
|
||||
LABEL org.opencontainers.image.url="https://github.com/thegeeklab/wp-git-clone"
|
||||
LABEL org.opencontainers.image.source="https://github.com/thegeeklab/wp-git-clone"
|
||||
LABEL org.opencontainers.image.documentation="https://github.com/thegeeklab/wp-git-clone"
|
||||
|
||||
RUN apk --update add --no-cache git openssh curl git-lfs && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
rm -rf /tmp/*
|
||||
|
||||
COPY --from=build /src/dist/wp-git-clone /bin/wp-git-clone
|
||||
ENTRYPOINT [ "/bin/wp-git-clone" ]
|
202
LICENSE
Normal file
202
LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Robert Kaussow <mail@thegeeklab.de>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
107
Makefile
Normal file
107
Makefile
Normal file
@ -0,0 +1,107 @@
|
||||
# renovate: datasource=github-releases depName=mvdan/gofumpt
|
||||
GOFUMPT_PACKAGE_VERSION := v0.5.0
|
||||
# renovate: datasource=github-releases depName=golangci/golangci-lint
|
||||
GOLANGCI_LINT_PACKAGE_VERSION := v1.55.2
|
||||
|
||||
EXECUTABLE := wp-git-clone
|
||||
|
||||
DIST := dist
|
||||
DIST_DIRS := $(DIST)
|
||||
IMPORT := github.com/thegeeklab/$(EXECUTABLE)
|
||||
|
||||
GO ?= go
|
||||
CWD ?= $(shell pwd)
|
||||
PACKAGES ?= $(shell go list ./...)
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@$(GOFUMPT_PACKAGE_VERSION)
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_PACKAGE_VERSION)
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
GOTESTSUM_PACKAGE ?= gotest.tools/gotestsum@latest
|
||||
|
||||
GENERATE ?=
|
||||
XGO_VERSION := go-1.21.x
|
||||
XGO_TARGETS ?= linux/amd64,linux/arm-6,linux/arm-7,linux/arm64
|
||||
|
||||
TARGETOS ?= linux
|
||||
TARGETARCH ?= amd64
|
||||
ifneq ("$(TARGETVARIANT)","")
|
||||
GOARM ?= $(subst v,,$(TARGETVARIANT))
|
||||
endif
|
||||
TAGS ?= netgo
|
||||
|
||||
ifndef VERSION
|
||||
ifneq ($(CI_COMMIT_TAG),)
|
||||
VERSION ?= $(subst v,,$(CI_COMMIT_TAG))
|
||||
else
|
||||
VERSION ?= $(shell git rev-parse --short HEAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DATE
|
||||
DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%S%z")
|
||||
endif
|
||||
|
||||
LDFLAGS += -s -w -X "main.BuildVersion=$(VERSION)" -X "main.BuildDate=$(DATE)"
|
||||
|
||||
.PHONY: all
|
||||
all: clean build
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(GO) clean -i ./...
|
||||
rm -rf $(DIST_DIRS)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GO) run $(GOFUMPT_PACKAGE) -extra -w $(SOURCES)
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
.PHONY: lint
|
||||
lint: golangci-lint
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
$(GO) generate $(GENERATE)
|
||||
|
||||
.PHONY: generate-docs
|
||||
generate-docs:
|
||||
$(GO) generate ./cmd/$(EXECUTABLE)/flags.go
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(GO) run $(GOTESTSUM_PACKAGE) --no-color=false -- -coverprofile=coverage.out $(PACKAGES)
|
||||
|
||||
.PHONY: build
|
||||
build: $(DIST)/$(EXECUTABLE)
|
||||
|
||||
$(DIST)/$(EXECUTABLE): $(SOURCES)
|
||||
GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) GOARM=$(GOARM) $(GO) build -v -tags '$(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -o $@ ./cmd/$(EXECUTABLE)
|
||||
|
||||
$(DIST_DIRS):
|
||||
mkdir -p $(DIST_DIRS)
|
||||
|
||||
.PHONY: xgo
|
||||
xgo: | $(DIST_DIRS)
|
||||
$(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -v -ldflags '-extldflags "-static" $(LDFLAGS)' -tags '$(TAGS)' -targets '$(XGO_TARGETS)' -out $(EXECUTABLE) --pkg cmd/$(EXECUTABLE) .
|
||||
cp /build/* $(CWD)/$(DIST)
|
||||
ls -l $(CWD)/$(DIST)
|
||||
|
||||
.PHONY: checksum
|
||||
checksum:
|
||||
cd $(DIST); $(foreach file,$(wildcard $(DIST)/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
|
||||
ls -l $(CWD)/$(DIST)
|
||||
|
||||
.PHONY: release
|
||||
release: xgo checksum
|
||||
|
||||
.PHONY: deps
|
||||
deps:
|
||||
$(GO) mod download
|
||||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(XGO_PACKAGE)
|
||||
$(GO) install $(GOTESTSUM_PACKAGE)
|
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# wp-git-clone
|
||||
|
||||
Woodpecker CI plugin to clone git repositories
|
||||
|
||||
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/wp-git-clone/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/wp-git-clone)
|
||||
[![Docker Hub](https://img.shields.io/badge/dockerhub-latest-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/thegeeklab/wp-git-clone)
|
||||
[![Quay.io](https://img.shields.io/badge/quay-latest-blue.svg?logo=docker&logoColor=white)](https://quay.io/repository/thegeeklab/wp-git-clone)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-git-clone)](https://goreportcard.com/report/github.com/thegeeklab/wp-git-clone)
|
||||
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-git-clone)](https://github.com/thegeeklab/wp-git-clone/graphs/contributors)
|
||||
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-git-clone)
|
||||
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-git-clone)](https://github.com/thegeeklab/wp-git-clone/blob/main/LICENSE)
|
||||
|
||||
Woodpecker CI plugin to clone git repositories. You can find the full documentation at [https://woodpecker-plugins.geekdocs.de](https://woodpecker-plugins.geekdocs.de/plugins/wp-git-clone).
|
||||
|
||||
## Contributors
|
||||
|
||||
Special thanks to all [contributors](https://github.com/thegeeklab/wp-git-clone/graphs/contributors). If you would like to contribute, please see the [instructions](https://github.com/thegeeklab/wp-git-clone/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache-2.0 License - see the [LICENSE](https://github.com/thegeeklab/wp-git-clone/blob/main/LICENSE) file for details.
|
57
cmd/wp-git-clone/docs.go
Normal file
57
cmd/wp-git-clone/docs.go
Normal file
@ -0,0 +1,57 @@
|
||||
//go:build generate
|
||||
// +build generate
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/thegeeklab/wp-git-clone/plugin"
|
||||
"github.com/thegeeklab/wp-plugin-go/docs"
|
||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
//go:embed templates/docs-data.yaml.tmpl
|
||||
var yamlTemplate embed.FS
|
||||
|
||||
func main() {
|
||||
settings := &plugin.Settings{}
|
||||
app := &cli.App{
|
||||
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
|
||||
}
|
||||
|
||||
out, err := toYAML(app)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fi, err := os.Create("../../docs/data/data-raw.yaml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer fi.Close()
|
||||
if _, err := fi.WriteString(out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func toYAML(app *cli.App) (string, error) {
|
||||
var w bytes.Buffer
|
||||
|
||||
yamlTmpl, err := template.New("docs").ParseFS(yamlTemplate, "templates/docs-data.yaml.tmpl")
|
||||
if err != nil {
|
||||
fmt.Println(yamlTmpl)
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := yamlTmpl.ExecuteTemplate(&w, "docs-data.yaml.tmpl", docs.GetTemplateData(app)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return w.String(), nil
|
||||
}
|
183
cmd/wp-git-clone/flags.go
Normal file
183
cmd/wp-git-clone/flags.go
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2020, the Drone Plugins project authors.
|
||||
// Copyright (c) 2021, Robert Kaussow <mail@thegeeklab.de>
|
||||
|
||||
// Use of this source code is governed by an Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/thegeeklab/wp-git-clone/plugin"
|
||||
"github.com/thegeeklab/wp-plugin-go/types"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// settingsFlags has the cli.Flags for the plugin.Settings.
|
||||
//
|
||||
//go:generate go run docs.go flags.go
|
||||
func settingsFlags(settings *plugin.Settings, category string) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "remote",
|
||||
Usage: "git remote url",
|
||||
EnvVars: []string{"PLUGIN_REMOTE", "CI_REPO_CLONE_URL"},
|
||||
Destination: &settings.Repo.RemoteURL,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "remote-ssh",
|
||||
Usage: "git clone ssh url",
|
||||
EnvVars: []string{"PLUGIN_REMOTE_SSH", "CI_REPO_CLONE_SSH_URL"},
|
||||
Destination: &settings.Repo.RemoteURL,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "workdir",
|
||||
Usage: "path to clone git repository",
|
||||
EnvVars: []string{"PLUGIN_WORKDIR", "CI_WORKSPACE"},
|
||||
Destination: &settings.WorkDir,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "sha",
|
||||
Usage: "git commit sha",
|
||||
EnvVars: []string{"PLUGIN_COMMIT_SHA", "CI_COMMIT_SHA"},
|
||||
Destination: &settings.Repo.CommitSha,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ref",
|
||||
Value: "refs/heads/main",
|
||||
Usage: "git commit ref",
|
||||
EnvVars: []string{"PLUGIN_COMMIT_REF", "CI_COMMIT_REF"},
|
||||
Destination: &settings.Repo.CommitRef,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "event",
|
||||
Value: "push",
|
||||
Usage: "pipeline event",
|
||||
EnvVars: []string{"CI_PIPELINE_EVENT"},
|
||||
Destination: &settings.Pipeline.Event,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "netrc.machine",
|
||||
Usage: "netrc machine",
|
||||
EnvVars: []string{"CI_NETRC_MACHINE"},
|
||||
Destination: &settings.Netrc.Machine,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "netrc.username",
|
||||
Usage: "netrc username",
|
||||
EnvVars: []string{"CI_NETRC_USERNAME"},
|
||||
Destination: &settings.Netrc.Password,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "netrc.password",
|
||||
Usage: "netrc password",
|
||||
EnvVars: []string{"CI_NETRC_PASSWORD"},
|
||||
Destination: &settings.Netrc.Password,
|
||||
Category: category,
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "depth",
|
||||
Usage: "clone depth",
|
||||
EnvVars: []string{"PLUGIN_DEPTH"},
|
||||
Destination: &settings.Depth,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "recursive",
|
||||
Usage: "clone submodules",
|
||||
EnvVars: []string{"PLUGIN_RECURSIVE"},
|
||||
Value: true,
|
||||
Destination: &settings.Recursive,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "tags",
|
||||
Usage: "clone tags, if not explicitly set and event is tag its default is true else false",
|
||||
EnvVars: []string{"PLUGIN_TAGS"},
|
||||
Destination: &settings.Tags,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "insecure-ssl-verify",
|
||||
Usage: "set SSL verification of the remote machine",
|
||||
EnvVars: []string{"PLUGIN_INSECURE_SSL_VERIFY"},
|
||||
Destination: &settings.Repo.InsecureSSLVerify,
|
||||
Value: false,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "submodule-update-remote",
|
||||
Usage: "update remote submodules",
|
||||
EnvVars: []string{"PLUGIN_SUBMODULES_UPDATE_REMOTE", "PLUGIN_SUBMODULE_UPDATE_REMOTE"},
|
||||
Destination: &settings.Repo.SubmoduleRemote,
|
||||
Category: category,
|
||||
},
|
||||
&cli.GenericFlag{
|
||||
Name: "submodule-override",
|
||||
Usage: "json map of submodule overrides",
|
||||
EnvVars: []string{"PLUGIN_SUBMODULE_OVERRIDE"},
|
||||
Value: &types.MapFlag{},
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "submodule-partial",
|
||||
Usage: "update submodules via partial clone",
|
||||
EnvVars: []string{"PLUGIN_SUBMODULES_PARTIAL", "PLUGIN_SUBMODULE_PARTIAL"},
|
||||
Value: true,
|
||||
Destination: &settings.Repo.SubmodulePartial,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "lfs",
|
||||
Usage: "whether to retrieve LFS content if available",
|
||||
EnvVars: []string{"PLUGIN_LFS"},
|
||||
Value: true,
|
||||
Destination: &settings.Lfs,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "branch",
|
||||
Usage: "change branch name",
|
||||
EnvVars: []string{"PLUGIN_BRANCH", "CI_COMMIT_BRANCH", "CI_REPO_DEFAULT_BRANCH"},
|
||||
Destination: &settings.Repo.Branch,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "partial",
|
||||
Usage: "enable/disable partial clone",
|
||||
EnvVars: []string{"PLUGIN_PARTIAL"},
|
||||
Value: false,
|
||||
Destination: &settings.Partial,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "safe-directory",
|
||||
Usage: "define/replace safe directories",
|
||||
EnvVars: []string{"PLUGIN_SAFE_DIRECTORY", "CI_WORKSPACE"},
|
||||
Destination: &settings.Repo.SafeDirectory,
|
||||
Category: category,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "use-ssh",
|
||||
Usage: "using ssh for git clone",
|
||||
EnvVars: []string{"PLUGIN_USE_SSH"},
|
||||
Value: false,
|
||||
Destination: &settings.UseSSH,
|
||||
Category: category,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ssh-key",
|
||||
Usage: "ssh key for ssh clone",
|
||||
EnvVars: []string{"PLUGIN_SSH_KEY"},
|
||||
Destination: &settings.SSHKey,
|
||||
Category: category,
|
||||
},
|
||||
}
|
||||
}
|
34
cmd/wp-git-clone/main.go
Normal file
34
cmd/wp-git-clone/main.go
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2020, the Drone Plugins project authors.
|
||||
// Copyright (c) 2021, Robert Kaussow <mail@thegeeklab.de>
|
||||
|
||||
// Use of this source code is governed by an Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/thegeeklab/wp-git-clone/plugin"
|
||||
|
||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
BuildVersion = "devel"
|
||||
BuildDate = "00000000"
|
||||
)
|
||||
|
||||
func main() {
|
||||
settings := &plugin.Settings{}
|
||||
options := wp.Options{
|
||||
Name: "wp-git-clone",
|
||||
Description: "Clone git repository",
|
||||
Version: BuildVersion,
|
||||
VersionMetadata: fmt.Sprintf("date=%s", BuildDate),
|
||||
Flags: settingsFlags(settings, wp.FlagsPluginCategory),
|
||||
}
|
||||
|
||||
plugin.New(options, settings).Run()
|
||||
}
|
14
cmd/wp-git-clone/templates/docs-data.yaml.tmpl
Normal file
14
cmd/wp-git-clone/templates/docs-data.yaml.tmpl
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
{{- if .GlobalArgs }}
|
||||
properties:
|
||||
{{- range $v := .GlobalArgs }}
|
||||
- name: {{ $v.Name }}
|
||||
{{- with $v.Description }}
|
||||
description: |
|
||||
{{ . }}
|
||||
{{- end }}
|
||||
{{- with $v.Default }}
|
||||
defaultvalue: {{ . }}
|
||||
{{- end }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
66
docs/content/_index.md
Normal file
66
docs/content/_index.md
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
title: wp-git-clone
|
||||
---
|
||||
|
||||
[![Build Status](https://ci.thegeeklab.de/api/badges/thegeeklab/wp-git-clone/status.svg)](https://ci.thegeeklab.de/repos/thegeeklab/wp-git-clone)
|
||||
[![Docker Hub](https://img.shields.io/badge/dockerhub-latest-blue.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/thegeeklab/wp-git-clone)
|
||||
[![Quay.io](https://img.shields.io/badge/quay-latest-blue.svg?logo=docker&logoColor=white)](https://quay.io/repository/thegeeklab/wp-git-clone)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/thegeeklab/wp-git-clone)](https://goreportcard.com/report/github.com/thegeeklab/wp-git-clone)
|
||||
[![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/wp-git-clone)](https://github.com/thegeeklab/wp-git-clone/graphs/contributors)
|
||||
[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/thegeeklab/wp-git-clone)
|
||||
[![License: Apache-2.0](https://img.shields.io/github/license/thegeeklab/wp-git-clone)](https://github.com/thegeeklab/wp-git-clone/blob/main/LICENSE)
|
||||
|
||||
Woodpecker CI plugin to clone git repositories.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- spellchecker-disable -->
|
||||
{{< toc >}}
|
||||
<!-- spellchecker-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Usage
|
||||
|
||||
```YAML
|
||||
clone:
|
||||
git:
|
||||
image: quay.io/thegeeklab/wp-git-clone
|
||||
settings:
|
||||
depth: 50
|
||||
lfs: false
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- spellchecker-disable -->
|
||||
{{< propertylist name=wp-git-clone.data sort=name >}}
|
||||
<!-- spellchecker-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## Build
|
||||
|
||||
Build the binary with the following command:
|
||||
|
||||
```Shell
|
||||
make build
|
||||
```
|
||||
|
||||
Build the container image with the following command:
|
||||
|
||||
```Shell
|
||||
docker build --file Containerfile.multiarch --tag thegeeklab/wp-git-clone .
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```Shell
|
||||
docker run --rm \
|
||||
-e CI_REPO_CLONE_URL=https://github.com/octocat/Hello-World.git \
|
||||
-e CI_PIPELINE_EVENT=push \
|
||||
-e CI_COMMIT_SHA=553c2077f0edc3d5dc5d17262f6aa498e69d6f8e \
|
||||
-e CI_COMMIT_REF=refs/heads/master \
|
||||
-e CI_WORKSPACE=/tmp/wp_git_testrepo \
|
||||
-v $(pwd):/build:z \
|
||||
-w /build \
|
||||
quay.io/thegeeklab/wp-git-clone
|
||||
```
|
100
docs/data/data.yaml
Normal file
100
docs/data/data.yaml
Normal file
@ -0,0 +1,100 @@
|
||||
---
|
||||
properties:
|
||||
- name: branch
|
||||
description: |
|
||||
Change branch name.
|
||||
|
||||
- name: ci_netrc_machine
|
||||
description: |
|
||||
Netrc machine.
|
||||
|
||||
- name: ci_netrc_password
|
||||
description: |
|
||||
Netrc password.
|
||||
|
||||
- name: ci_netrc_username
|
||||
description: |
|
||||
Metrc username.
|
||||
|
||||
- name: ci_pipeline_event
|
||||
description: |
|
||||
Pipeline event.
|
||||
defaultvalue: "push"
|
||||
|
||||
- name: commit_ref
|
||||
description: |
|
||||
Git commit ref.
|
||||
defaultvalue: "refs/heads/main"
|
||||
|
||||
- name: commit_sha
|
||||
description: |
|
||||
Git commit sha.
|
||||
|
||||
- name: depth
|
||||
description: |
|
||||
Clone depth.
|
||||
defaultvalue: 0
|
||||
|
||||
- name: insecure_ssl_verify
|
||||
description: |
|
||||
Set SSL verification of the remote machine.
|
||||
defaultvalue: false
|
||||
|
||||
- name: lfs
|
||||
description: |
|
||||
Whether to retrieve LFS content if available.
|
||||
defaultvalue: true
|
||||
|
||||
- name: partial
|
||||
description: |
|
||||
Enable/disable partial clone.
|
||||
defaultvalue: false
|
||||
|
||||
- name: recursive
|
||||
description: |
|
||||
Clone submodules.
|
||||
defaultvalue: true
|
||||
|
||||
- name: remote
|
||||
description: |
|
||||
Git remote HTTP clone url.
|
||||
|
||||
- name: remote_ssh
|
||||
description: |
|
||||
Git remote SSH clone url.
|
||||
|
||||
- name: safe_directory
|
||||
description: |
|
||||
Define/replace safe directories.
|
||||
|
||||
- name: ssh_key
|
||||
description: |
|
||||
SSH key for ssh clone.
|
||||
|
||||
- name: submodule_override
|
||||
description: |
|
||||
JSON map of submodule overrides.
|
||||
|
||||
- name: submodules_partial
|
||||
description: |
|
||||
Update submodules via partial clone (`depth=1`).
|
||||
defaultvalue: true
|
||||
|
||||
- name: submodules_update_remote
|
||||
description: |
|
||||
Update remote submodules.
|
||||
defaultvalue: false
|
||||
|
||||
- name: tags
|
||||
description: |
|
||||
Clone tags, if not explicitly set and event is tag its default is `true` else `false`.
|
||||
defaultvalue: false
|
||||
|
||||
- name: use_ssh
|
||||
description: |
|
||||
Using ssh for git clone.
|
||||
defaultvalue: false
|
||||
|
||||
- name: workdir
|
||||
description: |
|
||||
Path to clone git repository.
|
92
git/clone.go
Normal file
92
git/clone.go
Normal file
@ -0,0 +1,92 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// FetchSource fetches the source from remote.
|
||||
func FetchSource(ref string, tags bool, depth int, filter string) *execabs.Cmd {
|
||||
tagsOption := "--no-tags"
|
||||
|
||||
if tags {
|
||||
tagsOption = "--tags"
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"fetch",
|
||||
tagsOption,
|
||||
}
|
||||
|
||||
if depth != 0 {
|
||||
args = append(args, fmt.Sprintf("--depth=%d", depth))
|
||||
}
|
||||
|
||||
if filter != "" {
|
||||
args = append(args, "--filter="+filter)
|
||||
}
|
||||
|
||||
args = append(args, "origin")
|
||||
args = append(args, fmt.Sprintf("+%s:", ref))
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// FetchLFS fetches lfs.
|
||||
func FetchLFS() *execabs.Cmd {
|
||||
args := []string{
|
||||
"lfs",
|
||||
"fetch",
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// CheckoutHead handles head checkout.
|
||||
func CheckoutHead() *execabs.Cmd {
|
||||
args := []string{
|
||||
"checkout",
|
||||
"-qf",
|
||||
"FETCH_HEAD",
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// CheckoutSha handles commit checkout.
|
||||
func CheckoutSha(repo Repository) *execabs.Cmd {
|
||||
args := []string{
|
||||
"reset",
|
||||
"--hard",
|
||||
"-q",
|
||||
repo.CommitSha,
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// CheckoutLFS handles commit checkout.
|
||||
func CheckoutLFS() *execabs.Cmd {
|
||||
args := []string{
|
||||
"lfs",
|
||||
"checkout",
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
66
git/clone_test.go
Normal file
66
git/clone_test.go
Normal file
@ -0,0 +1,66 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestFetch tests if the arguments to `git fetch` are constructed properly.
|
||||
func TestFetch(t *testing.T) {
|
||||
testdata := []struct {
|
||||
ref string
|
||||
tags bool
|
||||
depth int
|
||||
exp []string
|
||||
}{
|
||||
{
|
||||
"refs/heads/master",
|
||||
false,
|
||||
0,
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"fetch",
|
||||
"--no-tags",
|
||||
"origin",
|
||||
"+refs/heads/master:",
|
||||
},
|
||||
},
|
||||
{
|
||||
"refs/heads/master",
|
||||
false,
|
||||
50,
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"fetch",
|
||||
"--no-tags",
|
||||
"--depth=50",
|
||||
"origin",
|
||||
"+refs/heads/master:",
|
||||
},
|
||||
},
|
||||
{
|
||||
"refs/heads/master",
|
||||
true,
|
||||
100,
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"fetch",
|
||||
"--tags",
|
||||
"--depth=100",
|
||||
"origin",
|
||||
"+refs/heads/master:",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, td := range testdata {
|
||||
c := FetchSource(td.ref, td.tags, td.depth, "")
|
||||
if len(c.Args) != len(td.exp) {
|
||||
t.Errorf("Expected: %s, got %s", td.exp, c.Args)
|
||||
}
|
||||
|
||||
for i := range c.Args {
|
||||
if c.Args[i] != td.exp[i] {
|
||||
t.Errorf("Expected: %s, got %s", td.exp, c.Args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
git/config.go
Normal file
70
git/config.go
Normal file
@ -0,0 +1,70 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// ConfigSSLVerify disables globally the git ssl verification.
|
||||
func ConfigSSLVerify(repo Repository) *execabs.Cmd {
|
||||
args := []string{
|
||||
"config",
|
||||
"--local",
|
||||
"http.sslVerify",
|
||||
strconv.FormatBool(repo.InsecureSSLVerify),
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// ConfigSafeDirectory disables globally the git ssl verification.
|
||||
func ConfigSafeDirectory(repo Repository) *execabs.Cmd {
|
||||
args := []string{
|
||||
"config",
|
||||
"--local",
|
||||
"--replace-all",
|
||||
"safe.directory",
|
||||
repo.SafeDirectory,
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// ConfigRemapSubmodule returns a git command that, when executed configures git to
|
||||
// remap submodule urls.
|
||||
func ConfigRemapSubmodule(name, url string) *execabs.Cmd {
|
||||
args := []string{
|
||||
"config",
|
||||
"--local",
|
||||
fmt.Sprintf("submodule.%s.url", name),
|
||||
url,
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
||||
|
||||
// ConfigSSHCommand sets custom SSH key.
|
||||
func ConfigSSHCommand(sshKey string) *execabs.Cmd {
|
||||
args := []string{
|
||||
"config",
|
||||
"--local",
|
||||
"core.sshCommand",
|
||||
"ssh -i " + sshKey,
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
27
git/init.go
Normal file
27
git/init.go
Normal file
@ -0,0 +1,27 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// RemoteRemove drops the defined remote from a git repo.
|
||||
func Init(repo Repository) *execabs.Cmd {
|
||||
args := []string{
|
||||
"init",
|
||||
}
|
||||
|
||||
if repo.Branch != "" {
|
||||
args = []string{
|
||||
"init",
|
||||
"-b",
|
||||
repo.Branch,
|
||||
}
|
||||
}
|
||||
|
||||
cmd := execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
|
||||
return cmd
|
||||
}
|
20
git/remote.go
Normal file
20
git/remote.go
Normal file
@ -0,0 +1,20 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// RemoteAdd adds an additional remote to a git repo.
|
||||
func RemoteAdd(url string) *execabs.Cmd {
|
||||
args := []string{
|
||||
"remote",
|
||||
"add",
|
||||
"origin",
|
||||
url,
|
||||
}
|
||||
|
||||
return execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
}
|
30
git/submodule.go
Normal file
30
git/submodule.go
Normal file
@ -0,0 +1,30 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// SubmoduleUpdate recursively initializes and updates submodules.
|
||||
func SubmoduleUpdate(repo Repository) *execabs.Cmd {
|
||||
args := []string{
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--recursive",
|
||||
}
|
||||
|
||||
if repo.SubmodulePartial {
|
||||
args = append(args, "--depth=1", "--recommend-shallow")
|
||||
}
|
||||
|
||||
cmd := execabs.Command(
|
||||
gitBin,
|
||||
args...,
|
||||
)
|
||||
|
||||
if repo.SubmoduleRemote {
|
||||
cmd.Args = append(cmd.Args, "--remote")
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
100
git/submodule_test.go
Normal file
100
git/submodule_test.go
Normal file
@ -0,0 +1,100 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestUpdateSubmodules tests if the arguments to `git submodule update`
|
||||
// are constructed properly.
|
||||
func TestUpdateSubmodules(t *testing.T) {
|
||||
tests := []struct {
|
||||
partial bool
|
||||
exp []string
|
||||
}{
|
||||
{
|
||||
false,
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--recursive",
|
||||
},
|
||||
},
|
||||
{
|
||||
true,
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--recursive",
|
||||
"--depth=1",
|
||||
"--recommend-shallow",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
repo := Repository{
|
||||
SubmoduleRemote: false,
|
||||
SubmodulePartial: tt.partial,
|
||||
}
|
||||
|
||||
c := SubmoduleUpdate(repo)
|
||||
if len(c.Args) != len(tt.exp) {
|
||||
t.Errorf("Expected: %s, got %s", tt.exp, c.Args)
|
||||
}
|
||||
|
||||
for i := range c.Args {
|
||||
if c.Args[i] != tt.exp[i] {
|
||||
t.Errorf("Expected: %s, got %s", tt.exp, c.Args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUpdateSubmodules tests if the arguments to `git submodule update`
|
||||
// are constructed properly.
|
||||
func TestUpdateSubmodulesRemote(t *testing.T) {
|
||||
tests := []struct {
|
||||
exp []string
|
||||
}{
|
||||
{
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--recursive",
|
||||
"--remote",
|
||||
},
|
||||
},
|
||||
{
|
||||
[]string{
|
||||
"/usr/bin/git",
|
||||
"submodule",
|
||||
"update",
|
||||
"--init",
|
||||
"--recursive",
|
||||
"--remote",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
repo := Repository{
|
||||
SubmoduleRemote: true,
|
||||
SubmodulePartial: false,
|
||||
}
|
||||
|
||||
c := SubmoduleUpdate(repo)
|
||||
if len(c.Args) != len(tt.exp) {
|
||||
t.Errorf("Expected: %s, got %s", tt.exp, c.Args)
|
||||
}
|
||||
|
||||
for i := range c.Args {
|
||||
if c.Args[i] != tt.exp[i] {
|
||||
t.Errorf("Expected: %s, got %s", tt.exp, c.Args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
git/type.go
Normal file
18
git/type.go
Normal file
@ -0,0 +1,18 @@
|
||||
package git
|
||||
|
||||
const gitBin = "/usr/bin/git"
|
||||
|
||||
type Repository struct {
|
||||
RemoteURL string
|
||||
RemoteSSH string
|
||||
Branch string
|
||||
CommitSha string
|
||||
CommitRef string
|
||||
Submodules map[string]string
|
||||
SubmoduleRemote bool
|
||||
SubmodulePartial bool
|
||||
|
||||
InsecureSSLVerify bool
|
||||
SafeDirectory string
|
||||
InitExists bool
|
||||
}
|
47
git/utils.go
Normal file
47
git/utils.go
Normal file
@ -0,0 +1,47 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
netrcFile = `
|
||||
machine %s
|
||||
login %s
|
||||
password %s
|
||||
`
|
||||
)
|
||||
|
||||
const (
|
||||
strictFilePerm = 0o600
|
||||
)
|
||||
|
||||
// WriteNetrc writes the netrc file.
|
||||
func WriteNetrc(machine, login, password string) error {
|
||||
netrcContent := fmt.Sprintf(
|
||||
netrcFile,
|
||||
machine,
|
||||
login,
|
||||
password,
|
||||
)
|
||||
|
||||
home := "/root"
|
||||
|
||||
if currentUser, err := user.Current(); err == nil {
|
||||
home = currentUser.HomeDir
|
||||
}
|
||||
|
||||
netpath := filepath.Join(
|
||||
home,
|
||||
".netrc",
|
||||
)
|
||||
|
||||
return os.WriteFile(
|
||||
netpath,
|
||||
[]byte(netrcContent),
|
||||
strictFilePerm,
|
||||
)
|
||||
}
|
32
go.mod
Normal file
32
go.mod
Normal file
@ -0,0 +1,32 @@
|
||||
module github.com/thegeeklab/wp-git-clone
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/cenkalti/backoff/v4 v4.2.1
|
||||
github.com/rs/zerolog v1.31.0
|
||||
github.com/thegeeklab/wp-plugin-go v1.3.0
|
||||
github.com/urfave/cli/v2 v2.26.0
|
||||
golang.org/x/sys v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
)
|
99
go.sum
Normal file
99
go.sum
Normal file
@ -0,0 +1,99 @@
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
|
||||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
|
||||
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
||||
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/thegeeklab/wp-plugin-go v1.3.0 h1:Yhz0dTDwXcbeaoyoPOXNDf2RzSoUixHuE+ML27cYy2E=
|
||||
github.com/thegeeklab/wp-plugin-go v1.3.0/go.mod h1:EUOH6XJ8G/bcd6gmM6a6vLeta+keyX9ul1Es0F0r2Lc=
|
||||
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
|
||||
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
207
plugin/impl.go
Normal file
207
plugin/impl.go
Normal file
@ -0,0 +1,207 @@
|
||||
// Copyright (c) 2023, Robert Kaussow <mail@thegeeklab.de>
|
||||
|
||||
// Use of this source code is governed by an Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thegeeklab/wp-git-clone/git"
|
||||
"github.com/thegeeklab/wp-plugin-go/types"
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
const (
|
||||
daemonBackoffMaxRetries = 3
|
||||
daemonBackoffInitialInterval = 2 * time.Second
|
||||
daemonBackoffMultiplier = 3.5
|
||||
)
|
||||
|
||||
var (
|
||||
ErrGitCloneDestintionNotValid = errors.New("destination not valid")
|
||||
ErrTypeAssertionFailed = errors.New("type assertion failed")
|
||||
)
|
||||
|
||||
//nolint:revive
|
||||
func (p *Plugin) run(ctx context.Context) error {
|
||||
if err := p.FlagsFromContext(); err != nil {
|
||||
return fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := p.Validate(); err != nil {
|
||||
return fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := p.Execute(); err != nil {
|
||||
return fmt.Errorf("execution failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate handles the settings validation of the plugin.
|
||||
func (p *Plugin) Validate() error {
|
||||
if p.Settings.WorkDir == "" {
|
||||
var err error
|
||||
if p.Settings.WorkDir, err = os.Getwd(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if p.Settings.Pipeline.Event == "tag" && !p.Settings.Tags {
|
||||
// tags clone not explicit set but pipeline is triggered by a tag
|
||||
// auto set tags cloning to true
|
||||
p.Settings.Tags = true
|
||||
}
|
||||
|
||||
if p.Settings.Tags && p.Settings.Partial {
|
||||
log.Warn().Msg("ignore partial clone as tags are fetched")
|
||||
|
||||
// if tag fetching is enabled per event or setting, disable partial clone
|
||||
p.Settings.Partial = false
|
||||
}
|
||||
|
||||
if p.Settings.Partial {
|
||||
p.Settings.Depth = 1
|
||||
p.Settings.Filter = "tree:0"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execute provides the implementation of the plugin.
|
||||
func (p *Plugin) Execute() error {
|
||||
cmds := make([]*execabs.Cmd, 0)
|
||||
|
||||
if err := os.Setenv("GIT_TERMINAL_PROMPT", "0"); err != nil {
|
||||
return err
|
||||
}
|
||||
// prevents git-lfs from retrieving any LFS files
|
||||
if err := os.Setenv("GIT_LFS_SKIP_SMUDGE", "1"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle init
|
||||
initPath := filepath.Join(p.Settings.WorkDir, ".git")
|
||||
|
||||
if err := os.MkdirAll(p.Settings.WorkDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint:nestif
|
||||
if _, err := os.Stat(initPath); os.IsNotExist(err) {
|
||||
if err := p.execCmd(git.Init(p.Settings.Repo), new(bytes.Buffer)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Settings.UseSSH {
|
||||
cmds = append(cmds, git.RemoteAdd(p.Settings.Repo.RemoteSSH))
|
||||
if p.Settings.SSHKey != "" {
|
||||
cmds = append(cmds, git.ConfigSSHCommand(p.Settings.SSHKey))
|
||||
}
|
||||
} else {
|
||||
cmds = append(cmds, git.RemoteAdd(p.Settings.Repo.RemoteURL))
|
||||
}
|
||||
}
|
||||
|
||||
cmds = append(cmds, git.ConfigSSLVerify(p.Settings.Repo))
|
||||
|
||||
if err := git.WriteNetrc(p.Settings.Netrc.Machine, p.Settings.Netrc.Login, p.Settings.Netrc.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle clone
|
||||
|
||||
if p.Settings.Repo.CommitSha == "" {
|
||||
// fetch and checkout by ref
|
||||
log.Info().Msg("no commit information: using head checkout")
|
||||
|
||||
cmds = append(cmds, git.FetchSource(p.Settings.Repo.CommitRef, p.Settings.Tags, p.Settings.Depth, p.Settings.Filter))
|
||||
cmds = append(cmds, git.CheckoutHead())
|
||||
} else {
|
||||
cmds = append(cmds, git.FetchSource(p.Settings.Repo.CommitSha, p.Settings.Tags, p.Settings.Depth, p.Settings.Filter))
|
||||
cmds = append(cmds, git.CheckoutSha(p.Settings.Repo))
|
||||
}
|
||||
|
||||
for name, submoduleURL := range p.Settings.Repo.Submodules {
|
||||
cmds = append(cmds, git.ConfigRemapSubmodule(name, submoduleURL))
|
||||
}
|
||||
|
||||
if p.Settings.Recursive {
|
||||
cmds = append(cmds, git.SubmoduleUpdate(p.Settings.Repo))
|
||||
}
|
||||
|
||||
if p.Settings.Lfs {
|
||||
cmds = append(cmds, git.FetchLFS())
|
||||
cmds = append(cmds, git.CheckoutLFS())
|
||||
}
|
||||
|
||||
for _, cmd := range cmds {
|
||||
log.Debug().Msgf("+ %s", strings.Join(cmd.Args, " "))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err := p.execCmd(cmd, buf)
|
||||
|
||||
switch {
|
||||
case err != nil && shouldRetry(buf.String()):
|
||||
backoffOps := func() error {
|
||||
// copy the original command
|
||||
//nolint:gosec
|
||||
retry := execabs.Command(cmd.Args[0], cmd.Args[1:]...)
|
||||
retry.Dir = cmd.Dir
|
||||
retry.Env = cmd.Env
|
||||
retry.Stdout = os.Stdout
|
||||
retry.Stderr = os.Stderr
|
||||
|
||||
trace(cmd)
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
backoffLog := func(err error, delay time.Duration) {
|
||||
log.Error().Msgf("failed to find remote ref: %v: retry in %s", err, delay.Truncate(time.Second))
|
||||
}
|
||||
|
||||
if err := backoff.RetryNotify(backoffOps, newBackoff(daemonBackoffMaxRetries), backoffLog); err != nil {
|
||||
return err
|
||||
}
|
||||
case err != nil:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) FlagsFromContext() error {
|
||||
submodules, ok := p.Context.Generic("submodule-override").(*types.MapFlag)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w: failed to read submodule-override input", ErrTypeAssertionFailed)
|
||||
}
|
||||
|
||||
p.Settings.Repo.Submodules = submodules.Get()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) execCmd(cmd *execabs.Cmd, buf *bytes.Buffer) error {
|
||||
cmd.Env = os.Environ()
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, buf)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, buf)
|
||||
cmd.Dir = p.Settings.WorkDir
|
||||
|
||||
fmt.Println(cmd.Dir)
|
||||
|
||||
return cmd.Run()
|
||||
}
|
243
plugin/impl_test.go
Normal file
243
plugin/impl_test.go
Normal file
@ -0,0 +1,243 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/thegeeklab/wp-git-clone/git"
|
||||
)
|
||||
|
||||
type testCommit struct {
|
||||
name string
|
||||
path string
|
||||
clone string
|
||||
event string
|
||||
commit string
|
||||
ref string
|
||||
file string
|
||||
data string
|
||||
dataSize int64
|
||||
recursive bool
|
||||
lfs bool
|
||||
}
|
||||
|
||||
// TestClone tests the ability to clone a specific commit into
|
||||
// a fresh, empty directory every time.
|
||||
func TestClone(t *testing.T) {
|
||||
for _, tt := range getCommits() {
|
||||
dir := setup()
|
||||
defer teardown(dir)
|
||||
|
||||
plugin := Plugin{
|
||||
Settings: &Settings{
|
||||
Repo: git.Repository{
|
||||
RemoteURL: tt.clone,
|
||||
CommitRef: tt.ref,
|
||||
CommitSha: tt.commit,
|
||||
},
|
||||
Pipeline: Pipeline{
|
||||
Event: tt.event,
|
||||
},
|
||||
WorkDir: filepath.Join(dir, tt.path),
|
||||
Recursive: tt.recursive,
|
||||
Lfs: tt.lfs,
|
||||
},
|
||||
}
|
||||
|
||||
if err := plugin.Execute(); err != nil {
|
||||
t.Errorf("Expected successful clone. Got error. %s.", err)
|
||||
}
|
||||
|
||||
if tt.data != "" {
|
||||
data := readFile(plugin.Settings.WorkDir, tt.file)
|
||||
if data != tt.data {
|
||||
t.Errorf("Expected %s to contain [%s]. Got [%s].", tt.file, tt.data, data)
|
||||
}
|
||||
}
|
||||
|
||||
if tt.dataSize != 0 {
|
||||
size := getFileSize(plugin.Settings.WorkDir, tt.file)
|
||||
if size != tt.dataSize {
|
||||
t.Errorf("Expected %s size to be [%d]. Got [%d].", tt.file, tt.dataSize, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCloneNonEmpty tests the ability to clone a specific commit into
|
||||
// a non-empty directory. This is useful if the git workspace is cached
|
||||
// and re-stored for every workflow.
|
||||
func TestCloneNonEmpty(t *testing.T) {
|
||||
dir := setup()
|
||||
defer teardown(dir)
|
||||
|
||||
for _, tt := range getCommits() {
|
||||
plugin := Plugin{
|
||||
Settings: &Settings{
|
||||
Repo: git.Repository{
|
||||
RemoteURL: tt.clone,
|
||||
CommitRef: tt.ref,
|
||||
CommitSha: tt.commit,
|
||||
},
|
||||
Pipeline: Pipeline{
|
||||
Event: tt.event,
|
||||
},
|
||||
WorkDir: filepath.Join(dir, tt.path),
|
||||
Recursive: tt.recursive,
|
||||
Lfs: tt.lfs,
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Println(plugin.Settings.Repo.CommitSha, tt.commit, fmt.Sprintf("%q", tt.data))
|
||||
|
||||
if err := plugin.Execute(); err != nil {
|
||||
t.Errorf("Expected successful clone. Got error. %s.", err)
|
||||
}
|
||||
|
||||
if tt.data != "" {
|
||||
data := readFile(plugin.Settings.WorkDir, tt.file)
|
||||
if data != tt.data {
|
||||
t.Errorf("Expected %s to contain [%q]. Got [%q].", tt.file, tt.data, data)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if tt.dataSize != 0 {
|
||||
size := getFileSize(plugin.Settings.WorkDir, tt.file)
|
||||
if size != tt.dataSize {
|
||||
t.Errorf("Expected %s size to be [%d]. Got [%d].", tt.file, tt.dataSize, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper function that will setup a temporary workspace
|
||||
// to which we can clone the repositroy.
|
||||
func setup() string {
|
||||
dir, _ := os.MkdirTemp("/tmp", "plugin_git_test_")
|
||||
_ = os.Mkdir(dir, os.ModePerm)
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
// helper function to delete the temporary workspace.
|
||||
func teardown(dir string) {
|
||||
os.RemoveAll(dir)
|
||||
}
|
||||
|
||||
// helper function to read a file in the temporary worskapce.
|
||||
func readFile(dir, file string) string {
|
||||
filename := filepath.Join(dir, file)
|
||||
fmt.Println(filename)
|
||||
data, _ := os.ReadFile(filename)
|
||||
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func getFileSize(dir, file string) int64 {
|
||||
filename := filepath.Join(dir, file)
|
||||
fi, _ := os.Stat(filename)
|
||||
|
||||
return fi.Size()
|
||||
}
|
||||
|
||||
func getCommits() []testCommit {
|
||||
return []testCommit{
|
||||
{
|
||||
name: "first commit",
|
||||
path: "octocat/Hello-World",
|
||||
clone: "https://github.com/octocat/Hello-World.git",
|
||||
event: "push",
|
||||
commit: "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
|
||||
ref: "refs/heads/master",
|
||||
file: "README",
|
||||
data: "Hello World!",
|
||||
},
|
||||
{
|
||||
name: "head commit",
|
||||
path: "octocat/Hello-World",
|
||||
clone: "https://github.com/octocat/Hello-World.git",
|
||||
event: "push",
|
||||
commit: "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
|
||||
ref: "refs/heads/master",
|
||||
file: "README",
|
||||
data: "Hello World!\n",
|
||||
},
|
||||
{
|
||||
name: "pull request commit",
|
||||
path: "octocat/Hello-World",
|
||||
clone: "https://github.com/octocat/Hello-World.git",
|
||||
event: "pull_request",
|
||||
commit: "762941318ee16e59dabbacb1b4049eec22f0d303",
|
||||
ref: "refs/pull/6/merge",
|
||||
file: "README",
|
||||
data: "Hello World!\n",
|
||||
},
|
||||
{
|
||||
name: "branch",
|
||||
path: "octocat/Hello-World",
|
||||
clone: "https://github.com/octocat/Hello-World.git",
|
||||
event: "push",
|
||||
commit: "b3cbd5bbd7e81436d2eee04537ea2b4c0cad4cdf",
|
||||
ref: "refs/heads/test",
|
||||
file: "CONTRIBUTING.md",
|
||||
data: "## Contributing\n",
|
||||
},
|
||||
{
|
||||
name: "tags",
|
||||
path: "github/mime-types",
|
||||
clone: "https://github.com/github/mime-types.git",
|
||||
event: "tag",
|
||||
commit: "bf68d60215a167c935bc5976b7d06a7ffb290926",
|
||||
ref: "refs/tags/v1.17",
|
||||
file: ".gitignore",
|
||||
data: "*.swp\n*~\n.rake_tasks~\nhtml\ndoc\npkg\npublish\ncoverage\n",
|
||||
},
|
||||
{
|
||||
name: "submodules",
|
||||
path: "test-assets/woodpecker-git-test-submodule",
|
||||
clone: "https://github.com/test-assets/woodpecker-git-test-submodule.git",
|
||||
event: "push",
|
||||
commit: "cc020eb6aaa601c13ca7b0d5db9d1ca694e7a003",
|
||||
ref: "refs/heads/main",
|
||||
file: "Hello-World/README",
|
||||
data: "Hello World!\n",
|
||||
recursive: true,
|
||||
},
|
||||
{
|
||||
name: "checkout with ref only",
|
||||
path: "octocat/Hello-World",
|
||||
clone: "https://github.com/octocat/Hello-World.git",
|
||||
event: "push",
|
||||
// commit: "a11fb45a696bf1d696fc9ab2c733f8f123aa4cf5",
|
||||
ref: "pull/2403/head",
|
||||
file: "README",
|
||||
data: "Hello World!\n\nsomething is changed!\n",
|
||||
},
|
||||
// test lfs, please do not change order, otherwise TestCloneNonEmpty will fail ###
|
||||
{
|
||||
name: "checkout with lfs skip",
|
||||
path: "test-assets/woodpecker-git-test-lfs",
|
||||
clone: "https://github.com/test-assets/woodpecker-git-test-lfs.git",
|
||||
event: "push",
|
||||
commit: "69d4dadb4c2899efb73c0095bb58a6454d133cef",
|
||||
ref: "refs/heads/main",
|
||||
file: "4M.bin",
|
||||
dataSize: 132,
|
||||
},
|
||||
{
|
||||
name: "checkout with lfs",
|
||||
path: "test-assets/woodpecker-git-test-lfs",
|
||||
clone: "https://github.com/test-assets/woodpecker-git-test-lfs.git",
|
||||
event: "push",
|
||||
commit: "69d4dadb4c2899efb73c0095bb58a6454d133cef",
|
||||
ref: "refs/heads/main",
|
||||
file: "4M.bin",
|
||||
dataSize: 4194304,
|
||||
lfs: true,
|
||||
},
|
||||
}
|
||||
}
|
56
plugin/plugin.go
Normal file
56
plugin/plugin.go
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2023, Robert Kaussow <mail@thegeeklab.de>
|
||||
|
||||
// Use of this source code is governed by an Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/thegeeklab/wp-git-clone/git"
|
||||
wp "github.com/thegeeklab/wp-plugin-go/plugin"
|
||||
)
|
||||
|
||||
// Plugin implements provide the plugin.
|
||||
type Plugin struct {
|
||||
*wp.Plugin
|
||||
Settings *Settings
|
||||
}
|
||||
|
||||
type Pipeline struct {
|
||||
Event string
|
||||
Number int
|
||||
}
|
||||
|
||||
type Netrc struct {
|
||||
Machine string
|
||||
Login string
|
||||
Password string
|
||||
}
|
||||
|
||||
// Settings for the plugin.
|
||||
type Settings struct {
|
||||
Depth int
|
||||
Recursive bool
|
||||
Tags bool
|
||||
Lfs bool
|
||||
Partial bool
|
||||
Filter string
|
||||
UseSSH bool
|
||||
SSHKey string
|
||||
WorkDir string
|
||||
|
||||
Pipeline Pipeline
|
||||
Netrc Netrc
|
||||
Repo git.Repository
|
||||
}
|
||||
|
||||
func New(options wp.Options, settings *Settings) *Plugin {
|
||||
p := &Plugin{}
|
||||
|
||||
options.Execute = p.run
|
||||
|
||||
p.Plugin = wp.New(options)
|
||||
p.Settings = settings
|
||||
|
||||
return p
|
||||
}
|
28
plugin/utils.go
Normal file
28
plugin/utils.go
Normal file
@ -0,0 +1,28 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"golang.org/x/sys/execabs"
|
||||
)
|
||||
|
||||
// shouldRetry returns true if the command should be re-executed. Currently
|
||||
// this only returns true if the remote ref does not exist.
|
||||
func shouldRetry(s string) bool {
|
||||
return strings.Contains(s, "find remote ref")
|
||||
}
|
||||
|
||||
func newBackoff(maxRetries uint64) backoff.BackOff {
|
||||
b := backoff.NewExponentialBackOff()
|
||||
b.InitialInterval = daemonBackoffInitialInterval
|
||||
b.Multiplier = daemonBackoffMultiplier
|
||||
|
||||
return backoff.WithMaxRetries(b, maxRetries)
|
||||
}
|
||||
|
||||
func trace(cmd *execabs.Cmd) {
|
||||
fmt.Fprintf(os.Stdout, "+ %s\n", strings.Join(cmd.Args, " "))
|
||||
}
|
4
renovate.json
Normal file
4
renovate.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>thegeeklab/renovate-presets:golang"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user