mirror of
https://github.com/drone-plugins/drone-pypi.git
synced 2026-06-04 18:24:00 +08:00
Merge branch 'origin-master'
This commit is contained in:
@@ -22,3 +22,5 @@ _testmain.go
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
drone-pypi
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
Use the PyPI plugin to deploy a Python package to a PyPI server.
|
||||
|
||||
* **repository** - The repository name (optional)
|
||||
* **username** - The username to login with (optional)
|
||||
* **password** - A password to login with (optional)
|
||||
* **distributions** - A list of distribution types to deploy (optional)
|
||||
|
||||
The following is an example configuration for your .drone.yml:
|
||||
|
||||
```yaml
|
||||
deploy:
|
||||
pypi:
|
||||
repository: https://pypi.python.org/pypi
|
||||
username: guido
|
||||
password: secret
|
||||
distributions:
|
||||
- sdist
|
||||
- bdist_wheel
|
||||
```
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
FROM alpine:3.2
|
||||
|
||||
RUN apk add -U \
|
||||
ca-certificates \
|
||||
py-pip \
|
||||
python \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& pip install --no-cache-dir --upgrade \
|
||||
pip \
|
||||
setuptools
|
||||
|
||||
ADD drone-pypi /bin/
|
||||
|
||||
ENTRYPOINT ["/bin/drone-pypi"]
|
||||
@@ -1,2 +1,65 @@
|
||||
# drone-pypi
|
||||
|
||||
Drone plugin for publishing to the Python package index
|
||||
|
||||
## Usage
|
||||
|
||||
Upload a source distribution to PyPI
|
||||
|
||||
```sh
|
||||
./drone-pypi <<EOF
|
||||
{
|
||||
"workspace": {
|
||||
"path": "/drone/my-module-py"
|
||||
}
|
||||
"vargs": {
|
||||
"username": "guido",
|
||||
"password": "secret"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Upload a source distribution and a wheel to PyPI
|
||||
|
||||
```sh
|
||||
./drone-pypi <<EOF
|
||||
{
|
||||
"workspace": {
|
||||
"path": "/drone/my-module-py"
|
||||
}
|
||||
"vargs": {
|
||||
"distributions": ["sdist", "bdist_wheel"],
|
||||
"username": "guido",
|
||||
"password": "secret"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Upload a source distribution to a private PyPI server, e.g. [simplepypi][]
|
||||
|
||||
```sh
|
||||
./drone-pypi <<EOF
|
||||
{
|
||||
"workspace": {
|
||||
"path": "/drone/my-module-py"
|
||||
}
|
||||
"vargs": {
|
||||
"repository": "https://pypi.example.com"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
[simplepypi]: https://github.com/steiza/simplepypi
|
||||
|
||||
## Docker
|
||||
|
||||
Build the Docker container using the `netgo` build tag to eliminate
|
||||
the CGO dependency:
|
||||
|
||||
```sh
|
||||
CGO_ENABLED=0 go build -a -tags netgo
|
||||
docker build --rm=true -t plugins/drone-pypi .
|
||||
```
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="110.4211"
|
||||
height="109.8461"
|
||||
id="svg2169"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45.1"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/bene/Desktop"
|
||||
sodipodi:docname="dessin-1.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs2171">
|
||||
<linearGradient
|
||||
id="linearGradient11301"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop11303"
|
||||
offset="0"
|
||||
style="stop-color:#ffe052;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop11305"
|
||||
offset="1"
|
||||
style="stop-color:#ffc331;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="168.1012"
|
||||
x2="147.77737"
|
||||
y1="111.92053"
|
||||
x1="89.136749"
|
||||
id="linearGradient11307"
|
||||
xlink:href="#linearGradient11301"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
id="linearGradient9515"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop9517"
|
||||
offset="0"
|
||||
style="stop-color:#387eb8;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop9519"
|
||||
offset="1"
|
||||
style="stop-color:#366994;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="131.85291"
|
||||
x2="110.14919"
|
||||
y1="77.070274"
|
||||
x1="55.549179"
|
||||
id="linearGradient9521"
|
||||
xlink:href="#linearGradient9515"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.24748737"
|
||||
inkscape:cx="-260.46312"
|
||||
inkscape:cy="316.02744"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
width="131.10236px"
|
||||
height="184.25197px"
|
||||
inkscape:window-width="872"
|
||||
inkscape:window-height="624"
|
||||
inkscape:window-x="5"
|
||||
inkscape:window-y="48" />
|
||||
<metadata
|
||||
id="metadata2174">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-473.36088,-251.72485)">
|
||||
<g
|
||||
id="g1894"
|
||||
transform="translate(428.42338,184.2561)">
|
||||
<path
|
||||
style="opacity:1;color:#000000;fill:url(#linearGradient9521);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M 99.75,67.46875 C 71.718268,67.468752 73.46875,79.625 73.46875,79.625 L 73.5,92.21875 L 100.25,92.21875 L 100.25,96 L 62.875,96 C 62.875,96 44.9375,93.965724 44.9375,122.25 C 44.937498,150.53427 60.59375,149.53125 60.59375,149.53125 L 69.9375,149.53125 L 69.9375,136.40625 C 69.9375,136.40625 69.433848,120.75 85.34375,120.75 C 101.25365,120.75 111.875,120.75 111.875,120.75 C 111.875,120.75 126.78125,120.99096 126.78125,106.34375 C 126.78125,91.696544 126.78125,82.125 126.78125,82.125 C 126.78125,82.124998 129.04443,67.46875 99.75,67.46875 z M 85,75.9375 C 87.661429,75.937498 89.8125,78.088571 89.8125,80.75 C 89.812502,83.411429 87.661429,85.5625 85,85.5625 C 82.338571,85.562502 80.1875,83.411429 80.1875,80.75 C 80.187498,78.088571 82.338571,75.9375 85,75.9375 z "
|
||||
id="path8615" />
|
||||
<path
|
||||
id="path8620"
|
||||
d="M 100.5461,177.31485 C 128.57784,177.31485 126.82735,165.1586 126.82735,165.1586 L 126.7961,152.56485 L 100.0461,152.56485 L 100.0461,148.7836 L 137.4211,148.7836 C 137.4211,148.7836 155.3586,150.81787 155.3586,122.53359 C 155.35861,94.249323 139.70235,95.252343 139.70235,95.252343 L 130.3586,95.252343 L 130.3586,108.37734 C 130.3586,108.37734 130.86226,124.03359 114.95235,124.03359 C 99.042448,124.03359 88.421098,124.03359 88.421098,124.03359 C 88.421098,124.03359 73.514848,123.79263 73.514848,138.43985 C 73.514848,153.08705 73.514848,162.6586 73.514848,162.6586 C 73.514848,162.6586 71.251668,177.31485 100.5461,177.31485 z M 115.2961,168.8461 C 112.63467,168.8461 110.4836,166.69503 110.4836,164.0336 C 110.4836,161.37217 112.63467,159.2211 115.2961,159.2211 C 117.95753,159.2211 120.1086,161.37217 120.1086,164.0336 C 120.10861,166.69503 117.95753,168.8461 115.2961,168.8461 z "
|
||||
style="opacity:1;color:#000000;fill:url(#linearGradient11307);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,137 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone-plugin-go/plugin"
|
||||
)
|
||||
|
||||
type Params struct {
|
||||
Distributions []string `json:"distributions"`
|
||||
Password *string `json:"password,omitempty"`
|
||||
Repository *string `json:"repository,omitempty"`
|
||||
Username *string `json:"username,omitempty"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
w := plugin.Workspace{}
|
||||
v := Params{}
|
||||
plugin.Param("workspace", &w)
|
||||
plugin.Param("vargs", &v)
|
||||
plugin.MustParse()
|
||||
|
||||
err := deploy(&w, &v)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func deploy(w *plugin.Workspace, v *Params) error {
|
||||
err := createConfig(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = uploadDist(w, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createConfig(v *Params) error {
|
||||
f, err := os.Create(path.Join(os.Getenv("HOME"), ".pypirc"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
buf := bufio.NewWriter(f)
|
||||
err = v.WriteConfig(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func uploadDist(w *plugin.Workspace, v *Params) error {
|
||||
cmd, err := v.Upload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Dir = w.Path
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
fmt.Println("$", strings.Join(cmd.Args, " "))
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteConfig writes a .pypirc to a supplied io.Writer.
|
||||
func (v *Params) WriteConfig(w io.Writer) error {
|
||||
repository := "https://pypi.python.org/pypi"
|
||||
if v.Repository != nil {
|
||||
repository = *v.Repository
|
||||
}
|
||||
username := "guido"
|
||||
if v.Username != nil {
|
||||
username = *v.Username
|
||||
}
|
||||
password := "secret"
|
||||
if v.Password != nil {
|
||||
password = *v.Password
|
||||
}
|
||||
_, err := io.WriteString(w, fmt.Sprintf(`[distutils]
|
||||
index-servers =
|
||||
pypi
|
||||
|
||||
[pypi]
|
||||
repository: %s
|
||||
username: %s
|
||||
password: %s
|
||||
`, repository, username, password))
|
||||
return err
|
||||
}
|
||||
|
||||
// Upload creates a setuptools upload command.
|
||||
func (v *Params) Upload() (*exec.Cmd, error) {
|
||||
distributions := []string{"sdist"}
|
||||
if len(v.Distributions) > 0 {
|
||||
distributions = v.Distributions
|
||||
}
|
||||
args := []string{"python", "setup.py"}
|
||||
for i := range distributions {
|
||||
args = append(args, distributions[i])
|
||||
}
|
||||
args = append(args, "upload")
|
||||
args = append(args, "-r")
|
||||
args = append(args, "pypi")
|
||||
return command(args)
|
||||
}
|
||||
|
||||
// Command builds a command using a variable length argument list.
|
||||
func command(args []string) (*exec.Cmd, error) {
|
||||
name := args[0]
|
||||
cmd := &exec.Cmd{
|
||||
Path: name,
|
||||
Args: args,
|
||||
}
|
||||
if filepath.Base(name) == name {
|
||||
lp, err := exec.LookPath(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd.Path = lp
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone-plugin-go/plugin"
|
||||
)
|
||||
|
||||
func TestDeploy(t *testing.T) {
|
||||
w := plugin.Workspace{
|
||||
Path: os.Getenv("DRONE_PYPI_PATH"),
|
||||
}
|
||||
repository := os.Getenv("DRONE_PYPI_REPOSITORY")
|
||||
username := os.Getenv("DRONE_PYPI_USERNAME")
|
||||
password := os.Getenv("DRONE_PYPI_PASSWORD")
|
||||
v := Params{
|
||||
Repository: &repository,
|
||||
Username: &username,
|
||||
Password: &password,
|
||||
Distributions: strings.Split(os.Getenv("DRONE_PYPI_DISTRIBUTIONS"), " "),
|
||||
}
|
||||
if w.Path == "" {
|
||||
t.Skip("DRONE_PYPI_PATH not set")
|
||||
}
|
||||
err := deploy(&w, &v)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func sPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
testdata := []struct {
|
||||
repository *string
|
||||
username *string
|
||||
password *string
|
||||
exp string
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
`[distutils]
|
||||
index-servers =
|
||||
pypi
|
||||
|
||||
[pypi]
|
||||
repository: https://pypi.python.org/pypi
|
||||
username: guido
|
||||
password: secret
|
||||
`,
|
||||
},
|
||||
{
|
||||
sPtr("https://pypi.example.com"),
|
||||
nil,
|
||||
nil,
|
||||
`[distutils]
|
||||
index-servers =
|
||||
pypi
|
||||
|
||||
[pypi]
|
||||
repository: https://pypi.example.com
|
||||
username: guido
|
||||
password: secret
|
||||
`,
|
||||
},
|
||||
{
|
||||
nil,
|
||||
sPtr("jqhacker"),
|
||||
sPtr("supersecret"),
|
||||
`[distutils]
|
||||
index-servers =
|
||||
pypi
|
||||
|
||||
[pypi]
|
||||
repository: https://pypi.python.org/pypi
|
||||
username: jqhacker
|
||||
password: supersecret
|
||||
`,
|
||||
},
|
||||
}
|
||||
for i, data := range testdata {
|
||||
v := Params{
|
||||
Repository: data.repository,
|
||||
Username: data.username,
|
||||
Password: data.password,
|
||||
Distributions: []string{},
|
||||
}
|
||||
var b bytes.Buffer
|
||||
v.WriteConfig(&b)
|
||||
if b.String() != data.exp {
|
||||
t.Errorf("Case %d: Expected %s, got %s\n", i, data.exp, b.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpload(t *testing.T) {
|
||||
testdata := []struct {
|
||||
distributions []string
|
||||
exp []string
|
||||
}{
|
||||
{
|
||||
[]string{},
|
||||
[]string{"python", "setup.py", "sdist", "upload", "-r", "pypi"},
|
||||
},
|
||||
{
|
||||
[]string{"sdist", "bdist_wheel"},
|
||||
[]string{"python", "setup.py", "sdist", "bdist_wheel", "upload", "-r", "pypi"},
|
||||
},
|
||||
}
|
||||
for i, data := range testdata {
|
||||
v := Params{Distributions: data.distributions}
|
||||
c, err := v.Upload()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(c.Args) != len(data.exp) {
|
||||
t.Errorf("Case %d: Expected %d, got %d", i, len(data.exp), len(c.Args))
|
||||
}
|
||||
for i := range c.Args {
|
||||
if c.Args[i] != data.exp[i] {
|
||||
t.Errorf("Case %d: Expected %s, got %s", i, strings.Join(data.exp, " "), strings.Join(c.Args, " "))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user