First commit

This commit is contained in:
Thomas Maurice 2017-01-10 22:09:34 +01:00
commit 59d3cfc7c8
No known key found for this signature in database
GPG key ID: 81A080685D4FDB96
8 changed files with 665 additions and 0 deletions

109
README.md Normal file
View file

@ -0,0 +1,109 @@
# Ansible role gitea - Install a gitea server
This role installs and manages a [gitea](https://gitea.io) server -
[Source code & screenshots](https://github.com/go-gitea/gitea).
Gitea is a Golang Git repository webapp, having the same look and feel as GitHub.
It is still under developpement, see "Disclaimer" if you can't make it work.
## Sample exemple of use in a playbook
The following have been tested with Debian 8, it should work on Ubuntu as well.
```yaml
- name: "Install gitea"
hosts: all
vars:
gitea_user: "gitea"
gitea_home: "/var/lib/gitea"
# To limit your users to 30 repos
gitea_user_repo_limit: 30
# Not to make use of any CDN
gitea_offline_mode: true
# Some 'rendering' options for your URLs
gitea_http_domain: git.yourdomain.fr
gitea_root_url: https://git.yourdomain.fr
# Here we assume we are behind a reverse proxy that will
# handle https for us, so we bind on localhost:3000 using HTTP
gitea_protocol: http
gitea_http_listen: 127.0.0.1
gitea_http_port: 3000
# SSH server configuration
gitea_ssh_listen: 0.0.0.0
gitea_ssh_port: 2222
# For URLs rendering again
gitea_ssh_domain: git.yourdomain.fr
gitea_start_ssh: true
gitea_ssh_port: 2222
gitea_secret_key: 3sp00ky5me
gitea_disable_gravatar: true
# To make at least your first user register
gitea_disable_registration: false
gitea_require_signin: true
gitea_enable_captcha: true
gitea_show_user_email: false
roles:
- gitea
```
## More detailed options
### General
* `gitea_user`: UNIX user used by Gitea
* `gitea_home`: Base directory to work
### Look and feel
* `gitea_app_name`: Displayed application name
* `gitea_show_user_email`: Do you share emails ? (true/false)
* `gitea_disable_gravatar`: Do you disable Gravatar ? (privacy and so on) (true/false)
* `gitea_offline_mode`: Same but with disabling CDNs (true/false)
* `gitea_disable_registration`: Do you disable user registration ? (true/false)
* `gitea_require_signin`: Do you require signin to see things (even public ones) ? (true/false)
* `gitea_enable_captcha`: Do you enable captcha ? (true/false)
* `gitea_secret_key`: Cookie secret key
### Limits
* `gitea_user_repo_limit`: Limit how many repos your user can have (-1 for unlimited)
### HTTP configuration
* `gitea_http_domain`: HTTP domain (displayed in your clone URLs, just the domain like git.foo.fr)
* `gitea_root_url`: Root URL used to access your web app (full URL)
* `gitea_protocol`: Listening protocol (http/https)
* `gitea_http_listen`: Bind address
* `gitea_http_port`: Bind port
* `gitea_disable_http_git`: Disable the use of Git over HTTP ? (true/false)
### SSH configuration
* `gitea_ssh_listen`: Bind address for the SSH server
* `gitea_ssh_domain`: SSH domain (displayed in your clone URLs)
* `gitea_start_ssh`: Do you start the SSH server ? (true/false)
* `gitea_ssh_port`: SSH bind port
## Disclaimer
This module is currently a work in progress. For now it is only able to install
gitea from the Github Release, in a fixed version for Linux amd64, on systems
using systemd.
This said, it should work on every major Linux distribution, it has been tested
successfully on Debian Jessie 64 bits.
Also it only supports the sqlite3 driver for now, but I'll improve soon.
## Contributing
Do not hesitate to make me a pull request, and when in doubt you can reach me on
Twitter [@thomas_maurice](https://twitter.com/thomas_maurice).
I also would be happy to fix the issues that would be opened.
## Author
This role is written by [Thomas Maurice](https://thomas.maurice.fr).

26
defaults/main.yml Normal file
View file

@ -0,0 +1,26 @@
gitea_app_name: "Gitea"
gitea_user: "gitea"
gitea_home: "/var/lib/gitea"
gitea_user_repo_limit: -1
gitea_http_domain: localhost
gitea_root_url: http://localhost:3000
gitea_protocol: http
gitea_http_listen: 127.0.0.1
gitea_http_port: 3000
gitea_disable_http_git: false
gitea_offline_mode: true
gitea_ssh_listen: 0.0.0.0
gitea_ssh_domain: localhost
gitea_start_ssh: true
gitea_ssh_port: 2222
gitea_secret_key: T0pS3cr31
gitea_show_user_email: false
gitea_disable_gravatar: true
gitea_disable_registration: false
gitea_require_signin: true
gitea_enable_captcha: true

5
handlers/main.yml Normal file
View file

@ -0,0 +1,5 @@
- name: "Restart gitea"
service: name=gitea state=restarted
- name: "Reload systemd"
shell: "systemctl daemon-reload"

6
tasks/create_user.yml Normal file
View file

@ -0,0 +1,6 @@
- name: "Create Gitea user"
user:
name: "{{ gitea_user }}"
comment: "Gitea user"
home: "{{ gitea_home }}"
shell: "/bin/false"

10
tasks/install_systemd.yml Normal file
View file

@ -0,0 +1,10 @@
- name: "Setup systemd service"
template:
src: gitea.service.j2
dest: /lib/systemd/system/gitea.service
owner: root
group: root
mode: 0644
notify:
- "Reload systemd"
- "Restart gitea"

42
tasks/main.yml Normal file
View file

@ -0,0 +1,42 @@
# TODO: variabilize this
- name: "Download the binary"
get_url:
url: "https://github.com/go-gitea/gitea/releases/download/v1.0.1/gitea-1.0.1-linux-amd64"
dest: /usr/local/bin/gitea
owner: root
group: root
mode: 0755
notify: "Restart gitea"
- include: create_user.yml
- name: "Create config and data directory"
file:
path: "{{ item }}"
state: directory
owner: "{{ gitea_user }}"
with_items:
- "/etc/gitea"
- "{{ gitea_home }}"
- "{{ gitea_home }}/data"
- "{{ gitea_home }}/custom"
- "{{ gitea_home }}/custom/https"
- "{{ gitea_home }}/custom/mailer"
# TODO: Support other systems than systemd
- include: install_systemd.yml
when: ansible_service_mgr == "systemd"
- name: "Configure gitea"
template:
src: gitea.ini.j2
dest: /etc/gitea/gitea.ini
owner: "{{ gitea_user }}"
mode: 0600
notify: "Restart gitea"
- name: "Service gitea"
service:
name: gitea
state: started
enabled: true

455
templates/gitea.ini.j2 Normal file
View file

@ -0,0 +1,455 @@
; App name that shows on every page title
APP_NAME = {{ gitea_app_name }}
; Change it if you run locally
RUN_USER = {{ gitea_user }}
; Either "dev", "prod" or "test", default is "dev"
RUN_MODE = prod
[repository]
ROOT = {{ gitea_home }}
SCRIPT_TYPE = bash
; Default ANSI charset
ANSI_CHARSET =
; Force every new repository to be private
FORCE_PRIVATE = false
; Global maximum creation limit of repository per user, -1 means no limit
MAX_CREATION_LIMIT = {{ gitea_user_repo_limit }}
; Mirror sync queue length, increase if mirror syncing starts hanging
MIRROR_QUEUE_LENGTH = 1000
; Patch test queue length, increase if pull request patch testing starts hanging
PULL_REQUEST_QUEUE_LENGTH = 1000
; Preferred Licenses to place at the top of the List
; Name must match file name in conf/license or custom/conf/license
PREFERRED_LICENSES = Apache License 2.0,MIT License
; Disable ability to interact with repositories by HTTP protocol
DISABLE_HTTP_GIT = {{ gitea_disable_http_git }}
[repository.editor]
; List of file extensions that should have line wraps in the CodeMirror editor
; Separate extensions with a comma. To line wrap files w/o extension, just put a comma
LINE_WRAP_EXTENSIONS = .txt,.md,.markdown,.mdown,.mkd,
; Valid file modes that have a preview API associated with them, such as api/v1/markdown
; Separate values by commas. Preview tab in edit mode won't show if the file extension doesn't match
PREVIEWABLE_FILE_MODES = markdown
[repository.upload]
; Whether repository file uploads are enabled. Defaults to `true`
ENABLED = true
; Path for uploads. Defaults to `data/tmp/uploads` (tmp gets deleted on gitea restart)
TEMP_PATH = {{ gitea_home }}/data/tmp/uploads
; One or more allowed types, e.g. image/jpeg|image/png. Nothing means any file type
ALLOWED_TYPES =
; Max size of each file in MB. Defaults to 3MB
FILE_MAX_SIZE = 3
; Max number of files per upload. Defaults to 5
MAX_FILES = 5
[ui]
; Number of repositories that are showed in one explore page
EXPLORE_PAGING_NUM = 20
; Number of issues that are showed in one page
ISSUE_PAGING_NUM = 10
; Number of maximum commits showed in one activity feed
FEED_MAX_COMMIT_NUM = 5
; Value of `theme-color` meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
THEME_COLOR_META_TAG = `#6cc644`
; Max size of files to be displayed (defaults is 8MiB)
MAX_DISPLAY_FILE_SIZE = 8388608
; Whether show the user email in the Explore Users page
SHOW_USER_EMAIL = {{ gitea_show_user_email }}
[ui.admin]
; Number of users that are showed in one page
USER_PAGING_NUM = 50
; Number of repos that are showed in one page
REPO_PAGING_NUM = 50
; Number of notices that are showed in one page
NOTICE_PAGING_NUM = 25
; Number of organization that are showed in one page
ORG_PAGING_NUM = 50
[ui.user]
; Number of repos that are showed in one page
REPO_PAGING_NUM = 15
[markdown]
; Enable hard line break extension
ENABLE_HARD_LINE_BREAK = false
; List of custom URL-Schemes that are allowed as links when rendering Markdown
; for example git,magnet
CUSTOM_URL_SCHEMES =
; List of file extensions that should be rendered/edited as Markdown
; Separate extensions with a comma. To render files w/o extension as markdown, just put a comma
FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
[server]
PROTOCOL = {{ gitea_protocol }}
DOMAIN = {{ gitea_http_domain }}
ROOT_URL = {{ gitea_root_url }}
HTTP_ADDR = {{ gitea_http_listen }}
HTTP_PORT = {{ gitea_http_port }}
; Permission for unix socket
UNIX_SOCKET_PERMISSION = 666
; Local (DMZ) URL for Gitea workers (such as SSH update) accessing web service.
; In most cases you do not need to change the default value.
; Alter it only if your SSH server node is not the same as HTTP node.
LOCAL_ROOT_URL = %(PROTOCOL)s://%(HTTP_ADDR)s:%(HTTP_PORT)s/
; Disable SSH feature when not available
DISABLE_SSH = false
; Whether use builtin SSH server or not.
START_SSH_SERVER = {{ gitea_start_ssh }}
; Domain name to be exposed in clone URL
SSH_DOMAIN = {{ gitea_ssh_domain }}
; Network interface builtin SSH server listens on
SSH_LISTEN_HOST = {{ gitea_ssh_listen }}
; Port number to be exposed in clone URL
SSH_PORT = {{ gitea_ssh_port }}
; Port number builtin SSH server listens on
SSH_LISTEN_PORT = %(SSH_PORT)s
; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
SSH_ROOT_PATH = {{ gitea_home }}/.ssh
; Directory to create temporary files when test publick key using ssh-keygen,
; default is system temporary directory.
SSH_KEY_TEST_PATH =
; Path to ssh-keygen, default is 'ssh-keygen' and let shell find out which one to call.
SSH_KEYGEN_PATH = ssh-keygen
; Indicate whether to check minimum key size with corresponding type
MINIMUM_KEY_SIZE_CHECK = false
; Disable CDN even in "prod" mode
OFFLINE_MODE = {{ gitea_offline_mode }}
DISABLE_ROUTER_LOG = false
; Generate steps:
; $ ./gitea cert -ca=true -duration=8760h0m0s -host=myhost.example.com
;
; Or from a .pfx file exported from the Windows certificate store (do
; not forget to export the private key):
; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys
; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
CERT_FILE = {{ gitea_home }}/custom/https/cert.pem
KEY_FILE = {{ gitea_home }}/custom/https/key.pem
; Upper level of template and static file path
; default is the path where Gitea is executed
STATIC_ROOT_PATH =
; Default path for App data
APP_DATA_PATH = {{ gitea_home }}/data
; Application level GZIP support
ENABLE_GZIP = false
; Landing page for non-logged users, can be "home" or "explore"
LANDING_PAGE = home
; Define allowed algorithms and their minimum key length (use -1 to disable a type)
[ssh.minimum_key_sizes]
ED25519 = 256
ECDSA = 256
RSA = 2048
DSA = 1024
[database]
; Either "mysql", "postgres" or "sqlite3", it's your choice
DB_TYPE = sqlite3
HOST = 127.0.0.1:3306
NAME = gitea
USER = root
PASSWD =
; For "postgres" only, either "disable", "require" or "verify-full"
SSL_MODE = disable
; For "sqlite3" and "tidb", use absolute path when you start as service
PATH = {{ gitea_home }}/data/gitea.db
[admin]
[security]
; Whether the installer is disabled
INSTALL_LOCK = true
; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
#@FDEWREWR&*(
SECRET_KEY = {{ gitea_secret_key }}
; Auto-login remember days
LOGIN_REMEMBER_DAYS = 7
COOKIE_USERNAME = gitea_awesome
COOKIE_REMEMBER_NAME = gitea_incredible
; Reverse proxy authentication header name of user name
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
; Sets the minimum password length for new Users
MIN_PASSWORD_LENGTH = 6
[service]
ACTIVE_CODE_LIVE_MINUTES = 180
RESET_PASSWD_CODE_LIVE_MINUTES = 180
; User need to confirm e-mail for registration
REGISTER_EMAIL_CONFIRM = false
; Does not allow register and admin create account only
DISABLE_REGISTRATION = {{ gitea_disable_registration }}
; User must sign in to view anything.
REQUIRE_SIGNIN_VIEW = {{ gitea_require_signin }}
; Mail notification
ENABLE_NOTIFY_MAIL = false
; More detail: https://github.com/go-gitea/gitea/issues/165
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
; Enable captcha validation for registration
ENABLE_CAPTCHA = {{ gitea_enable_captcha }}
; Default value for KeepEmailPrivate
; New user will get the value of this setting copied into their profile
DEFAULT_KEEP_EMAIL_PRIVATE = false
; Default value for the domain part of the user's email address in the git log
; if he has set KeepEmailPrivate true. The user's email replaced with a
; concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
NO_REPLY_ADDRESS = noreply.example.org
[webhook]
; Hook task queue length, increase if webhook shooting starts hanging
QUEUE_LENGTH = 1000
; Deliver timeout in seconds
DELIVER_TIMEOUT = 5
; Allow insecure certification
SKIP_TLS_VERIFY = false
; Number of history information in each page
PAGING_NUM = 10
[mailer]
ENABLED = false
; Buffer length of channel, keep it as it is if you don't know what it is.
SEND_BUFFER_LEN = 100
; Name displayed in mail title
SUBJECT = %(APP_NAME)s
; Mail server
; Gmail: smtp.gmail.com:587
; QQ: smtp.qq.com:465
; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used.
HOST =
; Disable HELO operation when hostname are different.
DISABLE_HELO =
; Custom hostname for HELO operation, default is from system.
HELO_HOSTNAME =
; Do not verify the certificate of the server. Only use this for self-signed certificates
SKIP_VERIFY =
; Use client certificate
USE_CERTIFICATE = false
CERT_FILE = {{ gitea_home }}/custom/mailer/cert.pem
KEY_FILE = {{ gitea_home }}/custom/mailer/key.pem
; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
FROM =
; Mailer user name and password
USER =
PASSWD =
; Use text/html as alternative format of content
ENABLE_HTML_ALTERNATIVE = false
; Enable sendmail (override SMTP)
USE_SENDMAIL = false
; Specifiy an alternative sendmail binary
SENDMAIL_PATH = sendmail
[cache]
; Either "memory", "redis", or "memcache", default is "memory"
ADAPTER = memory
; For "memory" only, GC interval in seconds, default is 60
INTERVAL = 60
; For "redis" and "memcache", connection host address
; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
; memcache: `127.0.0.1:11211`
HOST =
[session]
; Either "memory", "file", or "redis", default is "memory"
PROVIDER = file
; Provider config options
; memory: not have any config yet
; file: session file path, e.g. `data/sessions`
; redis: network=tcp,addr=:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
; mysql: go-sql-driver/mysql dsn config string, e.g. `root:password@/session_table`
PROVIDER_CONFIG = {{ gitea_home }}/data/sessions
; Session cookie name
COOKIE_NAME = i_like_gitea
; If you use session in https only, default is false
COOKIE_SECURE = false
; Enable set cookie, default is true
ENABLE_SET_COOKIE = true
; Session GC time interval, default is 86400
GC_INTERVAL_TIME = 86400
; Session life time, default is 86400
SESSION_LIFE_TIME = 86400
[picture]
AVATAR_UPLOAD_PATH = {{ gitea_home }}/data/avatars
; Chinese users can choose "duoshuo"
; or a custom avatar source, like: http://cn.gravatar.com/avatar/
GRAVATAR_SOURCE = gravatar
; This value will be forced to be true in offline mode.
DISABLE_GRAVATAR = {{ gitea_disable_gravatar }}
; Federated avatar lookup uses DNS to discover avatar associated
; with emails, see https://www.libravatar.org
; This value will be forced to be false in offline mode or Gravatar is disbaled.
ENABLE_FEDERATED_AVATAR = false
[attachment]
; Whether attachments are enabled. Defaults to `true`
ENABLE = true
; Path for attachments. Defaults to `data/attachments`
PATH = {{ gitea_home }}/data/attachments
; One or more allowed types, e.g. image/jpeg|image/png
ALLOWED_TYPES = image/jpeg|image/png
; Max size of each file. Defaults to 32MB
MAX_SIZE = 4
; Max number of files per upload. Defaults to 10
MAX_FILES = 5
[time]
; Specifies the format for fully outputed dates. Defaults to RFC1123
; Special supported values are ANSIC, UnixDate, RubyDate, RFC822, RFC822Z, RFC850, RFC1123, RFC1123Z, RFC3339, RFC3339Nano, Kitchen, Stamp, StampMilli, StampMicro and StampNano
; For more information about the format see http://golang.org/pkg/time/#pkg-constants
FORMAT =
[log]
ROOT_PATH = {{ gitea_home }}/log
; Either "console", "file", "conn", "smtp" or "database", default is "console"
; Use comma to separate multiple modes, e.g. "console, file"
MODE = file
; Buffer length of channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
LEVEL = Info
; For "console" mode only
[log.console]
LEVEL =
; For "file" mode only
[log.file]
LEVEL =
; This enables automated log rotate(switch of following options), default is true
LOG_ROTATE = true
; Max line number of single file, default is 1000000
MAX_LINES = 1000000
; Max size shift of single file, default is 28 means 1 << 28, 256MB
MAX_SIZE_SHIFT = 28
; Segment log daily, default is true
DAILY_ROTATE = true
; Expired days of log file(delete after max days), default is 7
MAX_DAYS = 7
; For "conn" mode only
[log.conn]
LEVEL =
; Reconnect host for every single message, default is false
RECONNECT_ON_MSG = false
; Try to reconnect when connection is lost, default is false
RECONNECT = false
; Either "tcp", "unix" or "udp", default is "tcp"
PROTOCOL = tcp
; Host address
ADDR =
; For "smtp" mode only
[log.smtp]
LEVEL =
; Name displayed in mail title, default is "Diagnostic message from server"
SUBJECT = Diagnostic message from server
; Mail server
HOST =
; Mailer user name and password
USER =
PASSWD =
; Receivers, can be one or more, e.g. 1@example.com,2@example.com
RECEIVERS =
; For "database" mode only
[log.database]
LEVEL =
; Either "mysql" or "postgres"
DRIVER =
; Based on xorm, e.g.: root:root@localhost/gitea?charset=utf8
CONN =
[cron]
; Enable running cron tasks periodically.
ENABLED = true
; Run cron tasks when Gitea starts.
RUN_AT_START = false
; Update mirrors
[cron.update_mirrors]
SCHEDULE = @every 10m
; Repository health check
[cron.repo_health_check]
SCHEDULE = @every 24h
TIMEOUT = 60s
; Arguments for command 'git fsck', e.g. "--unreachable --tags"
; see more on http://git-scm.com/docs/git-fsck/1.7.5
ARGS =
; Check repository statistics
[cron.check_repo_stats]
RUN_AT_START = true
SCHEDULE = @every 24h
[git]
; Disables highlight of added and removed changes
DISABLE_DIFF_HIGHLIGHT = false
; Max number of lines allowed of a single file in diff view
MAX_GIT_DIFF_LINES = 1000
; Max number of characters of a line allowed in diff view
MAX_GIT_DIFF_LINE_CHARACTERS = 500
; Max number of files shown in diff view
MAX_GIT_DIFF_FILES = 100
; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/1.7.5
GC_ARGS =
; Operation timeout in seconds
[git.timeout]
MIGRATE = 600
MIRROR = 300
CLONE = 300
PULL = 300
GC = 60
[mirror]
; Default interval in hours between each check
DEFAULT_INTERVAL = 8
[api]
; Max number of items will response in a page
MAX_RESPONSE_ITEMS = 50
[i18n]
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR
NAMES = English,简体中文,繁體中文(香港),繁體中文(台湾),Deutsch,Français,Nederlands,Latviešu,Русский,日本語,Español,Português do Brasil,Polski,български,Italiano,Suomalainen,Türkçe,čeština,Српски,Svenska,한국어
; Used for datetimepicker
[i18n.datelang]
en-US = en
zh-CN = zh
zh-HK = zh-TW
zh-TW = zh-TW
de-DE = de
fr-FR = fr
nl-NL = nl
lv-LV = lv
ru-RU = ru
ja-JP = ja
es-ES = es
pt-BR = pt-BR
pl-PL = pl
bg-BG = bg
it-IT = it
fi-FI = fi
tr-TR = tr
cs-CZ = cs-CZ
sr-SP = sr
sv-SE = sv
ko-KR = ko
; Extension mapping to highlight class
; e.g. .toml=ini
[highlight.mapping]
[other]
SHOW_FOOTER_BRANDING = false
; Show version information about Gitea and Go in the footer
SHOW_FOOTER_VERSION = true
; Show time of template execution in the footer
SHOW_FOOTER_TEMPLATE_LOAD_TIME = true

View file

@ -0,0 +1,12 @@
[Unit]
Description=Gitea git server
After=network.target
[Service]
User={{ gitea_user }}
ExecStart=/usr/local/bin/gitea web -c /etc/gitea/gitea.ini
Restart=on-failure
WorkingDirectory={{ gitea_home }}
[Install]
WantedBy=multi-user.target